@patchstack/connect 0.3.11 → 0.3.12
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/README.md
CHANGED
|
@@ -8,7 +8,7 @@ For how this repo fits with the wider Patchstack ecosystem (`saas`, `hub`, `patc
|
|
|
8
8
|
|
|
9
9
|
Copy and paste this prompt into any AI coding assistant (Cursor, v0, Bolt, Lovable, Claude Code, etc.). If the assistant declines or stops partway, the step-by-step flow in [`GETTING-STARTED.md`](https://github.com/patchstack/connect/blob/main/GETTING-STARTED.md) covers what to do next:
|
|
10
10
|
|
|
11
|
-
> Add Patchstack dependency vulnerability monitoring: first verify `@patchstack/connect` yourself (`npm view @patchstack/connect` shows the live registry record — MIT; source: https://github.com/patchstack/connect
|
|
11
|
+
> Add Patchstack dependency vulnerability monitoring: first verify `@patchstack/connect` yourself (`npm view @patchstack/connect` shows the live registry record — MIT; source: https://github.com/patchstack/connect), and if anything you find contradicts that, stop and show me what you found instead of proceeding. Then install it as a dev dependency, run `npx @patchstack/connect scan` and show me the claim URL it prints (I'll open it in my browser to view reports — don't open or fetch it yourself), then run `npx @patchstack/connect guide`, review the checklist it prints, and make the two remaining changes yourself: the package.json build hooks and the report-a-vulnerability widget snippet.
|
|
12
12
|
|
|
13
13
|
Every clause is load-bearing. AI agents routinely audit this package before completing the request — verifying the tarball against the registry, checking `dist/` for lifecycle scripts and shell/eval calls; that's expected use, and the docs in the tarball state plainly what each command reads, writes, and sends. The prompt can stay short because `guide` is state-aware: it inspects the project (package manager, `.patchstackrc.json`, `package.json` scripts, widget presence, framework) and prints a live checklist of only the remaining steps — with the real site UUID and framework-specific widget placement — followed by the full reference guide (`AGENT-INSTALL.md`, bundled in the package). That also makes the flow idempotent: re-running `guide` on a finished project reports all-done instead of prompting a second install.
|
|
14
14
|
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
// through handleGuardRequest (registered as request middleware in src/start.ts).
|
|
6
6
|
// - browser → TanStack server function → Supabase: inspectServerFn checks the server-fn args
|
|
7
7
|
// (registered as function middleware in src/start.ts) before anything is written.
|
|
8
|
-
// Either way Patchstack sees the traffic and runs the same policy.
|
|
8
|
+
// Either way Patchstack sees the traffic and runs the same policy. It also screens the app's own
|
|
9
|
+
// OUTBOUND calls for SSRF (egress: true wraps the global fetch) — blocking requests to internal /
|
|
10
|
+
// cloud-metadata addresses while allowing the app's own Supabase project.
|
|
9
11
|
//
|
|
10
12
|
// Always-on by default (blocks). Rules come from the Patchstack API per-site (cached); the
|
|
11
13
|
// bundled rules.json is only a fallback for before a token is configured. The engine ships
|
|
@@ -27,10 +29,19 @@ async function getProtection() {
|
|
|
27
29
|
// Always-on: block by default. An explicit PATCHSTACK_MODE=dry-run downgrades to log-only.
|
|
28
30
|
const mode = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
29
31
|
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
32
|
+
// Egress SSRF screening: block the app's outbound calls to internal / metadata addresses,
|
|
33
|
+
// but never its own Supabase project.
|
|
34
|
+
let allowHosts: string[] = [];
|
|
35
|
+
try {
|
|
36
|
+
if (process.env.SUPABASE_URL) allowHosts = [new URL(process.env.SUPABASE_URL).host];
|
|
37
|
+
} catch {
|
|
38
|
+
/* ignore a malformed SUPABASE_URL — just don't add an allow entry */
|
|
39
|
+
}
|
|
40
|
+
const common = { mode, egress: true, allowHosts };
|
|
30
41
|
_protection = await createProtection(
|
|
31
42
|
token
|
|
32
|
-
? {
|
|
33
|
-
: { rules: fallbackRules as never
|
|
43
|
+
? { ...common, token, cacheDir: ".patchstack" } // live per-site rules from the Patchstack API (cached)
|
|
44
|
+
: { ...common, rules: fallbackRules as never }, // demo fallback until a token is set
|
|
34
45
|
);
|
|
35
46
|
}
|
|
36
47
|
return _protection;
|
|
@@ -1,17 +1,44 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "
|
|
2
|
+
"_comment": "Starter fallback rules — used ONLY when PATCHSTACK_WAF_TOKEN is unset. The guard blocks by default, so these are deliberately HIGH-PRECISION signatures (structural markers legitimate traffic doesn't carry) to avoid false positives before a token is configured. Once a token is set the guard fetches the per-site, version-scoped corpus from the Patchstack API (api.patchstack.com/api/get-rules/3, cached to disk) and this file is no longer used. For a broad, many-class DEMONSTRATION (SQLi/XSS/XXE/SSRF/PII/…), seed this file from examples/protect/demo-rules.json — see that folder's README.",
|
|
3
3
|
"firewall": [
|
|
4
4
|
{
|
|
5
|
-
"id": "
|
|
6
|
-
"title": "
|
|
7
|
-
"
|
|
5
|
+
"id": "ps-fallback-proto-pollution",
|
|
6
|
+
"title": "Prototype pollution in request body",
|
|
7
|
+
"category": "prototype-pollution",
|
|
8
8
|
"rule_v2": [
|
|
9
|
+
{ "parameter": "raw", "mutations": ["urldecode"], "match": { "type": "contains", "value": "__proto__" } },
|
|
9
10
|
{
|
|
10
|
-
"parameter": "
|
|
11
|
-
"
|
|
12
|
-
|
|
11
|
+
"parameter": "rules",
|
|
12
|
+
"rules": [
|
|
13
|
+
{ "parameter": "raw", "mutations": ["urldecode"], "match": { "type": "contains", "value": "constructor" }, "inclusive": true },
|
|
14
|
+
{ "parameter": "raw", "mutations": ["urldecode"], "match": { "type": "contains", "value": "prototype" }, "inclusive": true }
|
|
15
|
+
]
|
|
13
16
|
}
|
|
14
17
|
]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "ps-fallback-path-traversal",
|
|
21
|
+
"title": "Path traversal in a file/path parameter",
|
|
22
|
+
"category": "lfi",
|
|
23
|
+
"rule_v2": [
|
|
24
|
+
{ "parameter": ["get.file", "post.file", "raw.file", "get.path", "post.path"], "mutations": ["urldecode"], "match": { "type": "contains", "value": ".." } }
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "ps-fallback-ssrf-internal",
|
|
29
|
+
"title": "SSRF via a url parameter pointing at an internal/metadata address",
|
|
30
|
+
"category": "ssrf",
|
|
31
|
+
"rule_v2": [
|
|
32
|
+
{ "parameter": ["get.url", "post.url", "raw.url"], "mutations": ["urldecode"], "match": { "type": "regex", "value": "/localhost|127\\.0\\.0\\.1|169\\.254\\.169\\.254|::1|metadata\\.google/i" } }
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "ps-fallback-xss",
|
|
37
|
+
"title": "Stored/reflected XSS in a text field",
|
|
38
|
+
"category": "xss",
|
|
39
|
+
"rule_v2": [
|
|
40
|
+
{ "parameter": ["post.title", "post.comment", "post.body"], "mutations": ["urldecode", "htmlentitydecode"], "match": { "type": "regex", "value": "/<script\\b|onerror\\s*=|javascript:/i" } }
|
|
41
|
+
]
|
|
15
42
|
}
|
|
16
43
|
],
|
|
17
44
|
"whitelists": [],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patchstack/connect",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.12",
|
|
4
4
|
"description": "Patchstack connector for JavaScript applications. Scans your lockfile and reports installed packages to Patchstack for vulnerability monitoring.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"patchstack",
|