Eh2406 opened a new issue, #431:
URL: https://github.com/apache/casbin-rs/issues/431

   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
   > 
   > Authorization bypass in `CachedEnforcer` allows a decision produced by one 
matcher section to be reused for the same request tuple under another matcher 
section. `CachedEnforcer::enforce_with_context` derives its cache key only from 
request values, so the `EnforceContext` selecting the `r`/`p`/`e`/`m` assertion 
set is ignored on cache lookup.
   > 
   > ## Impact
   > 
   > A remote user who can submit ordinary authorization requests can receive 
an allow decision from a more permissive matcher section when the application 
enables the `cached` feature and uses multiple assertion sets. This can cross 
application privilege tiers, such as replaying a public-section grant in an 
administrative section, without controlling the model, policy, or 
`EnforceContext`.
   > 
   > ## Proof of concept
   > 
   > Create `model.conf` with two request, policy, effect, and matcher 
sections. Give `alice` access only in section 1 and `bob` access only in 
section 2, then run this test with `cargo test --features cached --test 
poc_cache_context -- --nocapture`:
   > 
   > ```rust
   > use casbin::prelude::*;
   > use casbin::{CachedEnforcer, EnforceContext};
   > 
   > #[tokio::test]
   > async fn cache_context_mixup() {
   >     let plain = Enforcer::new("model.conf", "policy.csv").await.unwrap();
   >     assert!(!plain.enforce_with_context(
   >         EnforceContext::new("2"), ("alice", "data1", "read")
   >     ).unwrap());
   > 
   >     let cached = CachedEnforcer::new("model.conf", 
"policy.csv").await.unwrap();
   >     assert!(cached.enforce(("alice", "data1", "read")).unwrap());
   >     assert!(cached.enforce_with_context(
   >         EnforceContext::new("2"), ("alice", "data1", "read")
   >     ).unwrap()); // incorrect: section 2 denies alice
   > }
   > ```
   > 
   > At current HEAD, the uncached enforcer returns `false` for `alice` under 
section 2, but the cached enforcer returns `true` after section 1 has cached 
the identical request tuple:
   > 
   > ```text
   > plain section 1: true
   > plain section 2: false
   > cached section 1: true
   > cached section 2: true (expected false)
   > ```
   > 
   > The smoking gun is EnforceContext::get_cache_key() at src/enforcer.rs:95: 
a method that formats the four assertion names into EnforceContext{r2-p2-e2-m2} 
— exactly the discriminator this cache key needs. grep -rn get_cache_key over 
the whole crate (and over the published 2.20.0 tarball) returns its definition 
and nothing else. It is dead code; the call site that would have used it never 
materialised.


-- 
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