seamshield 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +124 -2
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +1096 -0
  4. package/package.json +58 -4
  5. package/rules/secrets.patterns.yaml +28 -0
  6. package/rules/ss-agent-mcp-inline-credentials.yaml +23 -0
  7. package/rules/ss-agent-overbroad-permissions.yaml +27 -0
  8. package/rules/ss-agent-secrets-in-agent-files.yaml +22 -0
  9. package/rules/ss-auth-admin-route-unprotected.yaml +24 -0
  10. package/rules/ss-auth-api-route-no-auth.yaml +24 -0
  11. package/rules/ss-auth-client-only-guard.yaml +24 -0
  12. package/rules/ss-auth-cors-wildcard-with-credentials.yaml +21 -0
  13. package/rules/ss-client-firebase-admin-in-client.yaml +23 -0
  14. package/rules/ss-client-next-public-secret.yaml +33 -0
  15. package/rules/ss-client-server-secret-env-in-client.yaml +24 -0
  16. package/rules/ss-client-supabase-service-role-in-client.yaml +24 -0
  17. package/rules/ss-convex-internal-not-internal.yaml +25 -0
  18. package/rules/ss-convex-mutation-no-auth.yaml +26 -0
  19. package/rules/ss-deps-hallucinated-package.yaml +16 -0
  20. package/rules/ss-deps-known-vuln.yaml +16 -0
  21. package/rules/ss-deps-no-lockfile.yaml +17 -0
  22. package/rules/ss-deps-unpinned-spec.yaml +22 -0
  23. package/rules/ss-firebase-open-rules.yaml +22 -0
  24. package/rules/ss-secrets-env-file-committed.yaml +21 -0
  25. package/rules/ss-secrets-generic-credential-assignment.yaml +26 -0
  26. package/rules/ss-secrets-hardcoded-provider-key.yaml +47 -0
  27. package/rules/ss-secrets-private-key-file.yaml +22 -0
  28. package/rules/ss-secrets-supabase-service-role-key.yaml +25 -0
  29. package/rules/ss-supabase-permissive-policy.yaml +22 -0
  30. package/rules/ss-supabase-rls-disabled.yaml +22 -0
  31. package/schemas/finding.schema.json +92 -0
  32. package/index.js +0 -2
@@ -0,0 +1,25 @@
1
+ id: ss/secrets/supabase-service-role-key
2
+ severity: block
3
+ title: Supabase service-role key hardcoded in source
4
+ description: >
5
+ A Supabase service-role JWT is written directly in source code. The
6
+ service-role key bypasses Row Level Security entirely — anyone holding it
7
+ can read and write every row in the database.
8
+ framework_ref: AI_AGENT_DROP_IN.md#default-security-stance
9
+ check:
10
+ type: regex
11
+ redact: true
12
+ include:
13
+ extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".json", ".yaml", ".yml", ".toml", ".html", ".svelte", ".vue", ".astro", ".md"]
14
+ exclude:
15
+ basenames: [".env*", "package-lock.json", "pnpm-lock.yaml", "yarn.lock", "*.min.js"]
16
+ patterns:
17
+ - name: supabase-service-role-jwt
18
+ regex: "eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]*(?:c2VydmljZV9yb2xl|NlcnZpY2Vfcm9sZ|zZXJ2aWNlX3JvbG)[A-Za-z0-9_-]*\\.[A-Za-z0-9_-]+"
19
+ fix:
20
+ summary: Remove the service-role key from source, keep it server-side only, and rotate it.
21
+ agent_prompt: >
22
+ Delete this hardcoded Supabase service-role key. Read it from a
23
+ server-only environment variable instead, never expose it to client
24
+ code, and tell the user to rotate the key in the Supabase dashboard
25
+ (Settings > API) because the committed value is burned.
@@ -0,0 +1,22 @@
1
+ id: ss/supabase/permissive-policy
2
+ severity: high
3
+ title: RLS policy that allows everything
4
+ description: >
5
+ A policy with USING (true) or WITH CHECK (true) grants the operation to
6
+ every requester, including the public anon role. RLS is technically on,
7
+ but it protects nothing.
8
+ framework_ref: AI_AGENT_DROP_IN.md#default-security-stance
9
+ check:
10
+ type: regex
11
+ include:
12
+ extensions: [".sql"]
13
+ patterns:
14
+ - name: policy-always-true
15
+ regex: "(?:USING|using|WITH CHECK|with check)\\s*\\(\\s*(?:true|TRUE)\\s*\\)"
16
+ fix:
17
+ summary: Scope the policy to the requesting user (for example auth.uid() = user_id).
18
+ agent_prompt: >
19
+ Rewrite this policy condition to scope access to the requesting user —
20
+ typically `auth.uid() = user_id` for ownership, or a role check for
21
+ shared data. If the table is genuinely public read-only, restrict the
22
+ policy to SELECT and add a comment explaining why.
@@ -0,0 +1,22 @@
1
+ id: ss/supabase/rls-disabled
2
+ severity: block
3
+ title: Row Level Security disabled on a table
4
+ description: >
5
+ A SQL migration disables Row Level Security. On Supabase the anon key is
6
+ public by design — RLS is the only thing standing between the internet
7
+ and this table's rows.
8
+ framework_ref: AI_AGENT_DROP_IN.md#default-security-stance
9
+ check:
10
+ type: regex
11
+ include:
12
+ extensions: [".sql"]
13
+ patterns:
14
+ - name: rls-disabled
15
+ regex: "(?:DISABLE ROW LEVEL SECURITY|disable row level security)"
16
+ fix:
17
+ summary: Re-enable RLS and write policies for the access the app actually needs.
18
+ agent_prompt: >
19
+ Change this statement to ENABLE ROW LEVEL SECURITY and add explicit
20
+ CREATE POLICY statements for each access pattern the app needs (for
21
+ example: users can select/update their own rows). If RLS was disabled
22
+ to debug a policy, fix the policy instead of removing the protection.
@@ -0,0 +1,92 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://seamshield.dev/schemas/finding.schema.json",
4
+ "title": "SeamShield Scan Finding",
5
+ "description": "Profile of seamshield-final-framework canonical-security-ir for scanner findings, extended with a `finding` object. Spine fields keep canonical IR semantics.",
6
+ "type": "object",
7
+ "required": [
8
+ "event_id",
9
+ "event_type",
10
+ "time",
11
+ "tenant",
12
+ "decision",
13
+ "route",
14
+ "engines",
15
+ "provenance",
16
+ "spans",
17
+ "finding"
18
+ ],
19
+ "properties": {
20
+ "event_id": { "type": "string", "minLength": 8 },
21
+ "event_type": { "const": "scan.finding" },
22
+ "time": { "type": "string", "format": "date-time" },
23
+ "tenant": { "type": "string" },
24
+ "decision": { "enum": ["deny", "scan"] },
25
+ "route": {
26
+ "type": "object",
27
+ "required": ["plane", "lane", "reason"],
28
+ "properties": {
29
+ "plane": { "const": "evidence" },
30
+ "lane": { "const": "cpu" },
31
+ "reason": {
32
+ "type": "array",
33
+ "items": { "type": "string" },
34
+ "minItems": 1
35
+ }
36
+ }
37
+ },
38
+ "engines": {
39
+ "type": "array",
40
+ "minItems": 1,
41
+ "items": {
42
+ "type": "object",
43
+ "required": ["name", "version"],
44
+ "properties": {
45
+ "name": { "type": "string" },
46
+ "version": { "type": "string" },
47
+ "role": { "type": "string" }
48
+ }
49
+ }
50
+ },
51
+ "provenance": {
52
+ "type": "object",
53
+ "required": ["policy_bundle_digest"],
54
+ "properties": {
55
+ "policy_bundle_digest": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
56
+ }
57
+ },
58
+ "spans": {
59
+ "type": "array",
60
+ "items": {
61
+ "type": "object",
62
+ "required": ["start", "end", "label", "evidence"],
63
+ "properties": {
64
+ "start": { "type": "integer", "minimum": 1 },
65
+ "end": { "type": "integer", "minimum": 1 },
66
+ "label": { "type": "string" },
67
+ "evidence": { "type": "string" }
68
+ }
69
+ }
70
+ },
71
+ "finding": {
72
+ "type": "object",
73
+ "required": ["rule_id", "severity", "title", "file", "line", "fix"],
74
+ "properties": {
75
+ "rule_id": { "type": "string", "pattern": "^ss/[a-z-]+/[a-z0-9-]+$" },
76
+ "severity": { "enum": ["block", "high", "warn", "info"] },
77
+ "title": { "type": "string" },
78
+ "file": { "type": "string" },
79
+ "line": { "type": "integer", "minimum": 1 },
80
+ "fix": {
81
+ "type": "object",
82
+ "required": ["summary", "agent_prompt"],
83
+ "properties": {
84
+ "summary": { "type": "string" },
85
+ "agent_prompt": { "type": "string" },
86
+ "doc_url": { "type": "string" }
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
package/index.js DELETED
@@ -1,2 +0,0 @@
1
- console.error("seamshield v0.0.1 is a placeholder — v0.1 (the real scanner) is in active development.");
2
- process.exit(1);