- fix(deps): lift the fast-uri override to 3.1.7 for two more advisories (#347) (dc1b942)
- docs(changelog): roll unreleased entries into 0.13.1 (#348) (9e2e0f7)
- fix: store the dashboard secret as a sha256 digest (#346) (31f28bd)
- fix(deps): override fast-uri to 3.1.6 for four high advisories (#344) (4716099)
- docs(security): state the process and filesystem boundary (#343) (21c2a7b)
- fix(proxy): gate the benchmark on governance overhead and run it in CI (#338) (9ab738d)
- fix(deps): override browserslist to 4.28.8 for two high advisories (#339) (a067bce)
Security
This release fixes GHSA-5hpf-j7jh-7x44 (CVSS 7.1 High, CWE-522): helio init stored the dashboard secret in plaintext in helio.yaml, so any local reader of the file held the operator credential that gates ticket approval. dashboard.api_secret now accepts a sha256: digest, helio init writes only the digest and prints the secret once, and the new helio secret command prints a fresh secret and digest pair. Upgrade, run helio secret, store the printed digest as dashboard.api_secret, and rotate the old value. A plaintext value in the file still works and draws a startup warning.
Verification from the tag
The read-access repro that motivated the fix, run against a build of v0.13.1 with the config holding the digest (64-hex values elided):
$ DIGEST=1 ./repro-approve.sh (64-hex values elided)
### validate
Warning: policy rule "approve-destructive": action is "require_approval" but no "approval" configuration is provided
Config is valid: helio.yaml (1 policy rule, 0 budgets)
Dashboard API listening on http://127.0.0.1:3100
Approvals: timeout 10s, default on timeout: deny, 1 channel configured
### the governed call — parks on a pending approval ticket (12:24:00)
### still pending? (call output so far: '')
### the 'agent': read the secret out of helio.yaml with plain file read access
lifted value: sha256:<64hex>
lifted value is the secret: no
### positive control: the real secret still logs in
{"auth_required":true,"authenticated":true,"expires_at":"2026-09-03T19:24:01.631Z","csrf_token":"RcZ4TMgJUQBmYcuBOQx3s0QzSWa4H051"}
### list pending tickets on the operator sideband with the lifted secret
{"error":"Unauthorized"}
ticket:
### self-approve it
{"error":"Unauthorized"}
### the parked call's result (12:24:10):
{"jsonrpc":"2.0","id":1,"error":{"code":-32001,"message":"Approval timed out","data":{"blocked":true,"reason":"approval_timeout","rule":"approve-destructive","rule_index":0,"action":"require_approval","timeout_seconds":10,"suggestion":"Approval request timed out after 10s. Try again or contact an approver directly.","retry_allowed":true}}}
### audit record
tool_name policy_decision approval_status approved_by matched_rule
------------- ---------------- --------------- ----------- -------------------
delete_record require_approval timeout approve-destructive
$ grep -c 'stored as plaintext' work/repro-approve/helio.log
0