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]

Reply via email to