Eh2406 opened a new issue, #426: URL: https://github.com/apache/casbin-rs/issues/426
Hi, I am Co-Lead of the Rust Cargo Team and was recently hired by the Rust Foundation to help triage AI discovered bugs. This bug was found with AI, namely scrutineer and Fable. Except where specifically labeled this report was written by me. I am posting this as a public issue as I have not received a response to our attempts to reach out on https://security.apache.org/report-code/, by email, and on your discord. From the AI: > ## Summary > > Phantom role grants from rejected grouping mutations. With the default `incremental` feature enabled, the internal grouping-policy mutators replay role-link additions and removals even when the model reports that the requested mutation was rejected. This creates authorization state that disagrees with the policy table, adapter, watcher events, cache invalidation, and the API's returned result. > > ## Impact > > An authenticated lower-privileged user who can reach an application-provided policy-mutation route can create a live, unlisted role grant by submitting a batch containing one duplicate rule and one new attacker-controlled rule. The same class of mismatch can silently revoke another user's live role link while the corresponding policy row remains visible. The phantom state affects enforcement until `load_policy()` or a process restart rebuilds role links. > > ## Proof of concept > > Create an integration test using the repository's RBAC example model and policy, then run it with the default features: > > ```rust > use casbin::prelude::*; > > #[tokio::test] > async fn phantom_role_grant() { > let mut enforcer = Enforcer::new( > "examples/rbac_model.conf", > "examples/rbac_policy.csv", > ) > .await > .unwrap(); > > assert!(!enforcer.enforce(("mallory", "data2", "read")).unwrap()); > > let changed = enforcer > .add_grouping_policies(vec![ > vec!["alice".into(), "data2_admin".into()], > vec!["mallory".into(), "data2_admin".into()], > ]) > .await > .unwrap(); > > assert!(!changed); > assert!(!enforcer > .get_grouping_policy() > .iter() > .any(|rule| rule[0] == "mallory")); > assert!(enforcer.enforce(("mallory", "data2", "read")).unwrap()); > } > ``` > > ```console > cargo test --features logging,explain --test poc_internal_api -- --nocapture --test-threads=1 poc_phantom_grant_batch_add > ``` > > The verified run returned `false` from `add_grouping_policies`, showed no `mallory` rule in `get_grouping_policy()`, and nevertheless changed `enforce(("mallory", "data2", "read"))` from `false` to `true`. If you rerun the test with `--no-default-features` made the final assertion fail, isolating the defect to incremental role-link replay. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
