{"_id":"@carjms/rls-guard","_rev":"4-b29c8dcd4324215b9dfb3339530215d2","name":"@carjms/rls-guard","dist-tags":{"latest":"0.7.0"},"versions":{"0.5.0":{"name":"@carjms/rls-guard","version":"0.5.0","keywords":["supabase","postgresql","rls","security","ci"],"license":"MIT","_id":"@carjms/rls-guard@0.5.0","maintainers":[{"name":"carjms","email":"carjms@naver.com"}],"homepage":"https://rls-guard-rose.vercel.app","bugs":{"url":"https://github.com/JIMyungSik/rls-guard/issues"},"bin":{"rls-guard":"cli.js"},"dist":{"shasum":"40c068a803f2b2dcbfbceea05d15dcf0f583a60f","tarball":"https://registry.npmjs.org/@carjms/rls-guard/-/rls-guard-0.5.0.tgz","fileCount":6,"integrity":"sha512-Kt/VJGLZSVLKSm6nxHn9DRP+OvQeGGP0EYeHTvTds4q83w8rLk/5xSs1it9+Np4g49+RpSq8Kj9m+l9Cr68j2w==","signatures":[{"sig":"MEQCIHSuWXqbXf5K33Xav+GfvssVww84/LdWJ+OHhFL97R0HAiB+c/4wkvLWHC3fUQ7Vj/E+mz9ZbQPL79FqrfirA0C6LA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35351},"type":"module","engines":{"node":">=20"},"gitHead":"cb89fd9ff5b8a8162272ed39b4a7a376552dc515","scripts":{"scan":"node cli.js","test":"node --test"},"_npmUser":{"name":"carjms","email":"carjms@naver.com"},"repository":{"url":"git+https://github.com/JIMyungSik/rls-guard.git","type":"git"},"_npmVersion":"11.17.0","description":"Static Supabase Row Level Security scanner for migrations and CI","directories":{},"_nodeVersion":"26.4.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/rls-guard_0.5.0_1784406326006_0.23835216488422528","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@carjms/rls-guard","version":"0.6.0","keywords":["supabase","postgresql","rls","security","ci"],"license":"MIT","_id":"@carjms/rls-guard@0.6.0","maintainers":[{"name":"carjms","email":"carjms@naver.com"}],"homepage":"https://rls-guard-rose.vercel.app","bugs":{"url":"https://github.com/JIMyungSik/rls-guard/issues"},"bin":{"rls-guard":"cli.js"},"dist":{"shasum":"294fc0222dee81e227c708d88b38ddcbc561b2ee","tarball":"https://registry.npmjs.org/@carjms/rls-guard/-/rls-guard-0.6.0.tgz","fileCount":6,"integrity":"sha512-evpWNbMYnX3WQi6ANChTed3OOo8VhDhnMkf3g2Uit7BXTgiRwX+Gqrzm9IC/1rm3+f2l7rirWyMo++ntqR+tCQ==","signatures":[{"sig":"MEYCIQDmpIUgYntYUmCX6UBxsybaKtMycX9F1uH8sFGW9BNbvAIhAJrTIdrRfpooqXYPzEBWw3zaeBRnME703W7BrlLXknPM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37082},"type":"module","engines":{"node":">=20"},"gitHead":"41920d13aa03df50679e5193c7207cfec986fcd0","scripts":{"scan":"node cli.js","test":"node --test"},"_npmUser":{"name":"carjms","email":"carjms@naver.com"},"repository":{"url":"git+https://github.com/JIMyungSik/rls-guard.git","type":"git"},"_npmVersion":"11.17.0","description":"Static Supabase Row Level Security scanner for migrations and CI","directories":{},"_nodeVersion":"26.4.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/rls-guard_0.6.0_1784415557000_0.27594213435293913","host":"s3://npm-registry-packages-npm-production"}},"0.6.1":{"name":"@carjms/rls-guard","version":"0.6.1","keywords":["supabase","postgresql","rls","security","ci"],"license":"MIT","_id":"@carjms/rls-guard@0.6.1","maintainers":[{"name":"carjms","email":"carjms@naver.com"}],"homepage":"https://rls-guard-rose.vercel.app","bugs":{"url":"https://github.com/JIMyungSik/rls-guard/issues"},"bin":{"rls-guard":"cli.js"},"dist":{"shasum":"3a861751015a7eb159332f5eb13647ae3d0d7f28","tarball":"https://registry.npmjs.org/@carjms/rls-guard/-/rls-guard-0.6.1.tgz","fileCount":6,"integrity":"sha512-vou4u1eOpTB1uVcoC7yrBkdWpEH3M5eU2CGVeeUKOPrmVIsx0j8t0zEjCg4gZNj5uDXTlTxZZe0UW5BaBaIDGA==","signatures":[{"sig":"MEQCIHjILCoCD1A1U92iesWbA+y6OZDFeipP5ut1jRNavFlWAiB5zL3XAsHlX+osz6pd/1LVWynvctmq5ImQjUrkTaCz9g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40291},"type":"module","engines":{"node":">=20"},"gitHead":"151c0c15dedf4791a2358fb6ef6212e8088c4e4d","scripts":{"scan":"node cli.js","test":"node --test"},"_npmUser":{"name":"carjms","email":"carjms@naver.com"},"repository":{"url":"git+https://github.com/JIMyungSik/rls-guard.git","type":"git"},"_npmVersion":"11.17.0","description":"Static Supabase Row Level Security scanner for migrations and CI","directories":{},"_nodeVersion":"26.4.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/rls-guard_0.6.1_1784416481533_0.7457851304671144","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@carjms/rls-guard","version":"0.7.0","description":"Static Supabase Row Level Security scanner for migrations and CI","license":"MIT","repository":{"type":"git","url":"git+https://github.com/JIMyungSik/rls-guard.git"},"homepage":"https://rls-guard-rose.vercel.app","keywords":["supabase","postgresql","rls","security","ci"],"publishConfig":{"access":"public"},"type":"module","bin":{"rls-guard":"cli.js"},"scripts":{"scan":"node cli.js","test":"node --test"},"engines":{"node":">=20"},"gitHead":"ad87b6d30a6525ac931c8354bfc72e2ee1612c85","_id":"@carjms/rls-guard@0.7.0","bugs":{"url":"https://github.com/JIMyungSik/rls-guard/issues"},"_nodeVersion":"26.4.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-gNTF/8YCzs3pdLgTEWwaR7VNTfPEnTuaIZ9Y6GMPvXbz7RA9lD4xbKYNkVqnFt33g7cYM4S0j3BK5Po0u5b+nA==","shasum":"37beedcd80ca9eb58bada761ac38576cb735a8c0","tarball":"https://registry.npmjs.org/@carjms/rls-guard/-/rls-guard-0.7.0.tgz","fileCount":6,"unpackedSize":43173,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDUCa2BUEyYApLVoDdVl9TRn4oMVmaAGrUCox2ngOdrowIhAJ6coQdnrZ9ObVcX4iWWRQkBcxTkDmqZBuJnhOAZmhG4"}]},"_npmUser":{"name":"carjms","email":"carjms@naver.com"},"directories":{},"maintainers":[{"name":"carjms","email":"carjms@naver.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/rls-guard_0.7.0_1784418360598_0.24651379243821192"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-18T20:25:25.829Z","modified":"2026-07-18T23:46:00.868Z","0.5.0":"2026-07-18T20:25:26.133Z","0.6.0":"2026-07-18T22:59:17.140Z","0.6.1":"2026-07-18T23:14:41.672Z","0.7.0":"2026-07-18T23:46:00.740Z"},"bugs":{"url":"https://github.com/JIMyungSik/rls-guard/issues"},"license":"MIT","homepage":"https://rls-guard-rose.vercel.app","keywords":["supabase","postgresql","rls","security","ci"],"repository":{"type":"git","url":"git+https://github.com/JIMyungSik/rls-guard.git"},"description":"Static Supabase Row Level Security scanner for migrations and CI","maintainers":[{"name":"carjms","email":"carjms@naver.com"}],"readme":"# 🛡 RLS Guard\n\n**Free Supabase Row Level Security scanner — paste your migration SQL, get an instant audit with fix SQL.**\n\n<p>\n  <a href=\"https://rls-guard-rose.vercel.app\"><img alt=\"Live demo\" src=\"https://img.shields.io/badge/demo-live-3ecf8e\"></a>\n  <img alt=\"Client-side only\" src=\"https://img.shields.io/badge/privacy-client--side%20only-blue\">\n  <img alt=\"License\" src=\"https://img.shields.io/badge/license-MIT-lightgrey\">\n</p>\n\n### ▶ Try it now: **[rls-guard-rose.vercel.app](https://rls-guard-rose.vercel.app)**\n\nPaste your `supabase/migrations/*.sql` and get findings in milliseconds — no signup, no upload:\n\n![Scan results with severity badges and fix SQL](docs/demo-results.png)\n\nMost Supabase data leaks come from the same handful of misconfigurations: tables exposed without RLS, `USING (true)` policies, INSERT policies without `WITH CHECK`, roles that bypass RLS, and views that silently bypass RLS. RLS Guard reconstructs the final state of pasted migrations—including policy, grant, role, function, and view changes—and scans for 13 of these classes, with fix SQL for each finding.\n\n## Why client-side matters\n\nA security tool that uploads your schema is itself a security risk. RLS Guard runs **entirely in your browser** — your SQL is never uploaded, stored, or logged (verify in the network tab). It even flags service keys or connection strings accidentally pasted into SQL, without storing them.\n\n## Rules\n\n| Rule | Detects | Severity |\n|---|---|---|\n| RLS-001 | Table in exposed schema without RLS enabled | Critical |\n| RLS-002 | RLS enabled but zero policies (silent lockout) | Medium |\n| RLS-003 | Always-true policy conditions (`USING (true)`) | High/Critical |\n| RLS-004 | INSERT policy missing `WITH CHECK` | High |\n| RLS-005 | Owner/tenant column never referenced by any policy | High |\n| RLS-006 | Write policies applied to PUBLIC role | High |\n| RLS-007 | Policy omits every row condition (PostgreSQL defaults it to TRUE) | High/Critical |\n| STORAGE-001 | Storage write policy is not constrained by `bucket_id` | High |\n| GRANT-001 | Write privileges granted to `anon`/`public` | High |\n| ROLE-001 | Database roles with `SUPERUSER` or `BYPASSRLS` | Critical |\n| FUNC-001 | `SECURITY DEFINER` functions with unpinned search_path | High |\n| VIEW-001 | Views without `security_invoker` (RLS bypass) | High |\n| SECRET-001 | Service keys / connection strings inside SQL | Critical |\n\n## Run locally\n\nAny static server works:\n\n```bash\nnpx serve .\n```\n\nOr use the engine directly in Node:\n\n```js\nimport { scanSql } from './scanner.js';\nconst report = scanSql(mySql);\nconsole.log(report.score, report.findings);\n```\n\n## Use in CI\n\nScan one migration, several ordered migrations, or stdin. The CLI exits with status 1 when it finds a Critical issue by default, so it can fail a CI job:\n\n```bash\nnode cli.js supabase/migrations/*.sql\nnode cli.js --fail-on high supabase/migrations/*.sql\ncat migration.sql | node cli.js --json\nnode cli.js --format markdown --output rls-guard-report.md supabase/migrations/*.sql\nnode cli.js --format sarif --output rls-guard.sarif supabase/migrations/*.sql\nnode cli.js --ignore-rule RLS-002 --fail-on high supabase/migrations/*.sql\n```\n\n`--format` accepts `text`, `json`, `markdown`, or GitHub Code Scanning-compatible `sarif`. `--output` writes a review-ready artifact for pull requests and audit records. `--fail-on` accepts `critical`, `high`, `medium`, or `low`. Repeat `--ignore-rule RULE-ID` only for rules your team has reviewed and accepted; ignored findings are removed from the report and exit-code decision, and the report records the ignored rule IDs and count. Findings never include matched secret values.\n\nRun the pinned public package without installing it globally:\n\n```bash\nnpx @carjms/rls-guard@0.7.0 --fail-on high supabase/migrations/*.sql\n```\n\n## Limitations (honest ones)\n\nRegex-based static analysis on a lightweight SQL splitter — it does not implement the full PostgreSQL grammar, distinguish overloaded functions that share a name, or test live access. It only reconstructs the ordered SQL supplied in one scan. **A clean scan is not a security guarantee.** Treat it as a fast first pass, not an audit.\n\nFound a false positive or a rule idea? [Open an issue](../../issues) — feedback directly shapes the ruleset.\n\nNever post keys, connection strings, customer data, or private migrations in an issue. Reduce rule feedback to synthetic SQL, or use the [security policy](SECURITY.md) for a private product vulnerability report.\n\n## Roadmap\n\n- [x] CI-ready CLI with severity thresholds and JSON output\n- [x] Migration state reconstruction for policy, grant, role, function, and view changes\n- [x] Storage object write-policy bucket checks\n- [x] SARIF output for GitHub Code Scanning\n- [x] Auditable per-rule exceptions for project-specific CI adoption\n\nIf any of these would be useful to you, a ⭐ and an issue telling me which one helps prioritize.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}