You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: security & correctness hardening from deep-dive audit (#98)
* fix(security): harden notify.sh against injection and config code-exec
- Parse ~/.stack-nudge/config as allowlisted STACKNUDGE_* KEY=VALUE data
instead of `source`-ing it, so a write to that file can no longer run
arbitrary code on every hook event.
- Pass the cwd basename (project name) and tty path into osascript via the
environment and read them back with `system attribute`, instead of
interpolating them into the AppleScript text — closes AppleScript/shell
injection via a maliciously named project directory or tty path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: serialise CodexQuotaProbe reads to avoid cacheKey/cached data race
read() mutated the cacheKey/cached stored properties from a global concurrent
queue, so overlapping quota polls could race and corrupt the cache. Route
read() through a private serial queue so those properties are only ever
touched on one queue.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: harden notify.sh phrase rendering and permission FIFO
- Render voice phrases via explicit %s substitution instead of using the
phrase as a printf format string, so stray % tokens (especially in
user-supplied phrases.user.json entries) can't corrupt the spoken output.
- Create the permission FIFO inside a private mktemp -d directory (0700,
CSPRNG-named) rather than a 16-bit $RANDOM /tmp path a local attacker
could guess and race; clean up the directory in the EXIT trap.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: validate prebuilt bundle and escape plist XML in install.sh
- Verify build/StackNudge.app carries an executable before removing the
installed copy, so a corrupt artifact can't leave the user with no app.
- XML-escape labels, paths and program args written into the launchd plist
so an install dir containing & < > can't produce a plist launchd rejects.
- Document STACKNUDGE_DEBUG in notify.conf.example.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: correctness fixes in dedup, deny-FIFO, device-flow and antigravity
- EventStore.append: abs() the dedup timestamp delta so an out-of-order event
isn't silently dropped as a false duplicate.
- actOnSelected: write the FIFO on Deny too (not only Allow), so a Deny no
longer leaves the agent's hook blocked until its 550s timeout.
- pollGithubSignIn: enforce the device code's expiry (RFC 8628) instead of
polling forever, and back off by at least 5s on slow_down.
- AntigravityLocalServer: raise the semaphore backstop above URLSession's
resource timeout so the request completion releases the wait.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: require update checksum and surface silent API/parse failures
- Updater: refuse to install when a release has no .sha256 sidecar (every
release publishes one) instead of silently skipping checksum verification.
- GitHubAPI.parse: detect the GraphQL {errors:[...]} envelope on HTTP 200 and
log it, rather than treating an errored response as "no PR found".
- Phrases.defaults: log when the phrase-loading subprocess fails to launch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: surface silent listener, quota and credential failures in the UI
Addresses the three remaining high-severity deep-dive findings — each a
failure that happened with no user-visible signal:
- Socket-bind failure: startListener records nav.listenerError (cleared on a
successful bind) and the Events tab shows an orange banner, instead of the
panel silently receiving no events with only a stderr line in the log.
- Unofficial Anthropic quota endpoint: QuotaProbe now distinguishes "had a
token but the request/parse failed" from "no token", so the Usage tab shows
"quota unavailable" instead of "Loading usage…" forever when the endpoint
shape changes.
- Plaintext OAuth token: keep preferring ~/.claude/.credentials.json (it's
intentional — avoids Claude Code's periodic Keychain re-prompt) but warn in
Settings -> Usage when that path is active, since any same-user process can
read the file.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0 commit comments