shipwarden 0.2.0 → 0.2.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.
- package/package.json +1 -1
- package/src/rules/secrets.js +2 -0
- package/src/rules/web.js +6 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shipwarden",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Free security scanner and launch checklist for apps built with Lovable, Bolt, Cursor and v0: Supabase RLS, Firebase rules, leaked keys, unprotected endpoints, missing privacy policy and 404 pages.",
|
|
5
5
|
"homepage": "https://github.com/patrickballard/shipwarden#readme",
|
|
6
6
|
"repository": {
|
package/src/rules/secrets.js
CHANGED
|
@@ -87,6 +87,8 @@ export const publicEnvSecret = {
|
|
|
87
87
|
for (const m of file.content.matchAll(PUBLIC_VAR)) {
|
|
88
88
|
const [name, prefix, rest] = m;
|
|
89
89
|
if (seen.has(name) || /PUBLISHABLE|ANON/.test(rest)) continue;
|
|
90
|
+
const lineStart = file.content.lastIndexOf('\n', m.index) + 1;
|
|
91
|
+
if (/^\s*(#|\/\/|\*)/.test(file.content.slice(lineStart, m.index))) continue; // commented out
|
|
90
92
|
const critical = CRITICAL_NAME.test(rest);
|
|
91
93
|
if (!critical && !AI_KEY_NAME.test(rest)) continue;
|
|
92
94
|
// The ai-key-in-browser finding already covers an AI key used from browser code.
|
package/src/rules/web.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EDGE_FUNCTION, ROUTE_HANDLER, hasDirective, isServerEndpoint, lineAt, makeFinding } from '../util.js';
|
|
1
|
+
import { EDGE_FUNCTION, ROUTE_HANDLER, hasDirective, isServerEndpoint, lineAt, looksLikePlaceholder, makeFinding } from '../util.js';
|
|
2
2
|
|
|
3
3
|
const MUTATING_EXPORT = /export\s+(?:async\s+)?function\s+(POST|PUT|PATCH|DELETE)\b|export\s+const\s+(POST|PUT|PATCH|DELETE)\s*=|\bas\s+(POST|PUT|PATCH|DELETE)\b/;
|
|
4
4
|
|
|
@@ -177,8 +177,11 @@ export const committedEnvFile = {
|
|
|
177
177
|
severity: 'high',
|
|
178
178
|
check(file, ctx) {
|
|
179
179
|
if (!ctx.tracked || !ENV_FILE.test(file.path) || ENV_TEMPLATE.test(file.path)) return [];
|
|
180
|
-
const
|
|
181
|
-
|
|
180
|
+
const vars = [...file.content.matchAll(/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*['"]?([^\s'"#][^\n'"]*)/gm)];
|
|
181
|
+
// Public values and local-only dev settings (localhost databases, "password") aren't leaks.
|
|
182
|
+
const secrets = vars
|
|
183
|
+
.filter(([, name, value]) => !PUBLIC_PREFIX.test(name) && !/localhost|127\.0\.0\.1|0\.0\.0\.0|host\.docker\.internal/.test(value) && !looksLikePlaceholder(value) && !/^(password|secret|changeme|true|false|\d+|development|production|test)$/i.test(value))
|
|
184
|
+
.map(([, name]) => name);
|
|
182
185
|
if (!secrets.length) return [];
|
|
183
186
|
const shown = secrets.slice(0, 5).map((n) => `\`${n}\``).join(', ');
|
|
184
187
|
return [
|