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

   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 from synthetic policy rows in Casbin. When the 
selected policy type has no rows, `Enforcer` binds every policy token to an 
empty string, evaluates the matcher against that fabricated row, and converts a 
true result directly to `Allow`. `StringAdapter::load_filtered_policy` can 
compose with this behavior by silently discarding all rows during a filtered 
load.
   > 
   > ## Impact
   > 
   > An unprivileged caller who can supply values to `Enforcer::enforce` can 
receive an allow decision that no administrator policy authorizes. Empty 
request fields can match the fabricated row directly, and an empty policy-side 
regular expression can match arbitrary request values; in the verified chain, a 
normal filtered load leaves the policy empty and produces an authorization 
bypass on a stock allow-effect model.
   > 
   > ## Proof of concept
   > 
   > Add the following as `tests/poc.rs`, then run `cargo test --test poc -- 
--nocapture`:
   > 
   > ```rust
   > use casbin::prelude::*;
   > 
   > #[tokio::test]
   > async fn empty_policy_can_allow() {
   >     let model = DefaultModel::from_str(
   >         "[request_definition]\n         r = sub, obj, act\n\n         
[policy_definition]\n         p = sub, obj, act\n\n         [policy_effect]\n   
      e = some(where (p.eft == allow))\n\n         [matchers]\n         m = 
r.sub == p.sub && r.obj == p.obj && regexMatch(r.act, p.act)\n",
   >     )
   >     .await
   >     .unwrap();
   >     let enforcer = Enforcer::new(model, 
MemoryAdapter::default()).await.unwrap();
   > 
   >     assert!(enforcer.enforce(("", "", "DELETE")).unwrap());
   > }
   > ```
   > 
   > The verified output is a passing assertion: `enforce(("", "", "DELETE"))` 
returns `true` even though the adapter contains no policy rows. The composed 
reproducer additionally showed that `StringAdapter::load_filtered_policy(Filter 
{ p: ["alice"], ... })` leaves the policy set empty and changes `enforce(("", 
"", ""))` from `false` after a full load to `true` after the filtered load.


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