Install any skill in seconds. Free to start, no credit card required.
Get Started Free →A skill to evaluate how secure Firestore security rules are. Use this when Firestore security rules are updated to ensure that the generated rules are extremely secure and robust.
.claude/skills/firebase-security-rules-auditor/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | -8% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 38% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 72% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 36% | 0% |
| case-12 | ✗→✓ | ▲ Improved | -5% | 0% |
This skill acts as an auditor for Firebase Security Rules, evaluating them against a rigorous set of criteria to ensure they are secure, robust, and correctly implemented.
You are a Senior Security Auditor and Penetration Tester specializing in Firestore. Your goal is to find "the hole in the wall." Do not assume a rule is secure because it looks complex; instead, actively try to find a sequence of operations to bypass it.
a valid document and then 'update' it into an invalid or malicious state (e.g., changing their role, bypassing size limits, or corrupting data types)?
(request.resource.data) for sensitive fields like 'role', 'isAdmin', or 'ownerId'? Carefully consider the source for that authority.
purpose? (e.g., In a collaboration app, can collaborators actually read the data? If not, the rules are "broken" or will force insecure workarounds).
label it as a "Resource Exhaustion/DoS" risk.
timestamp'?
\hasOnly()\ or \diff()\. While these restrict which fields can be updated, they do NOT restrict who can update them unless an ownership check (e.g., \resource.data.uid == request.auth.uid\) is also present. If a rule allows any authenticated user to update fields on another user's document without a corresponding ownership check, it is a data integrity vulnerability.
The admin bootstrapping process is limited in this app. If the rules use a single hardcoded admin email (e.g., checking request.auth.token.email == 'admin@example.com'), this should NOT count against the score as long as:
themselves or leave an escalation risk open.
total validation bypass.
(create vs update) on critical fields
bypasses that only impact the user's own data, lack of size limits, missing minor type checks or over-permissive read access on non-sensitive fields.
access via secure ACLs.
Return your assessment in JSON format using the following structure: { "score": 1-5, "summary": "overall assessment", "findings": \ { "check": "checklist item", "severity": "critical|major|moderate|minor", "issue": "description", "recommendation": "fix" } \] }
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 6,430 | 17,751 | +176% | 1 | 1 | 0% | 869 | 2,240 | +158% | 0 | 0 | — |
case-02 | fail→pass | 13,840 | 7,378 | -47% | 1 | 1 | 0% | 2,359 | 2,166 | -8% | 0 | 0 | — |
case-03 | fail→pass | 22,292 | 25,310 | +14% | 1 | 1 | 0% | 2,309 | 3,181 | +38% | 0 | 0 | — |
case-04 | fail→fail | 11,069 | 19,920 | +80% | 1 | 1 | 0% | 1,756 | 3,143 | +79% | 0 | 0 | — |
case-05 | fail→pass | 7,981 | 9,045 | +13% | 1 | 1 | 0% | 1,552 | 2,676 | +72% | 0 | 0 | — |
case-06 | pass→fail | 17,449 | 10,195 | -42% | 1 | 1 | 0% | 1,392 | 2,062 | +48% | 0 | 0 | — |
case-07 | pass→pass | 7,827 | 10,592 | +35% | 1 | 1 | 0% | 1,442 | 2,782 | +93% | 0 | 0 | — |
case-08 | pass→pass | 6,350 | 8,020 | +26% | 1 | 1 | 0% | 1,272 | 2,374 | +87% | 0 | 0 | — |
case-09 | pass→pass | 9,189 | 9,440 | +3% | 1 | 1 | 0% | 1,575 | 2,673 | +70% | 0 | 0 | — |
case-10 | pass→pass | 10,419 | 8,841 | -15% | 1 | 1 | 0% | 2,059 | 2,585 | +26% | 0 | 0 | — |
case-11 | fail→pass | 7,097 | 4,483 | -37% | 1 | 1 | 0% | 1,240 | 1,690 | +36% | 0 | 0 | — |
case-12 | fail→pass | 10,026 | 4,925 | -51% | 1 | 1 | 0% | 1,787 | 1,703 | -5% | 0 | 0 | — |
case-13 | fail→pass | 5,983 | 5,023 | -16% | 1 | 1 | 0% | 1,051 | 1,730 | +65% | 0 | 0 | — |
case-14 | pass→pass | 6,182 | 5,454 | -12% | 1 | 1 | 0% | 1,188 | 1,873 | +58% | 0 | 0 | — |
case-15 | fail→pass | 10,162 | 5,054 | -50% | 1 | 1 | 0% | 1,811 | 1,673 | -8% | 0 | 0 | — |
case-16 | pass→pass | 7,118 | 10,125 | +42% | 1 | 1 | 0% | 1,372 | 2,650 | +93% | 0 | 0 | — |
case-17 | pass→pass | 8,665 | 8,221 | -5% | 1 | 1 | 0% | 1,575 | 2,294 | +46% | 0 | 0 | — |
case-18 | pass→pass | 24,306 | 9,599 | -61% | 1 | 1 | 0% | 2,507 | 2,802 | +12% | 0 | 0 | — |
case-19 | pass→pass | 8,777 | 6,654 | -24% | 1 | 1 | 0% | 1,613 | 2,084 | +29% | 0 | 0 | — |
case-20 | pass→pass | 12,203 | 16,285 | +33% | 1 | 1 | 0% | 1,511 | 2,598 | +72% | 0 | 0 | — |
case-21 | fail→fail | 9,469 | 6,544 | -31% | 1 | 1 | 0% | 1,656 | 2,002 | +21% | 0 | 0 | — |
case-22 | pass→pass | 9,909 | 7,139 | -28% | 1 | 1 | 0% | 1,805 | 2,143 | +19% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +27 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/23/2026 | +11% |
Other measured skills in the registry, with their headline benchmark lift.