Skip to content

security: hash-pin deps (Q8) + behavioral anomaly alarms (Q10) - #3

Merged
sudsali merged 1 commit into
mainfrom
appsec/hardening-q8-q10
Jul 21, 2026
Merged

security: hash-pin deps (Q8) + behavioral anomaly alarms (Q10)#3
sudsali merged 1 commit into
mainfrom
appsec/hardening-q8-q10

Conversation

@sudsali

@sudsali sudsali commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Addresses two findings from the AppSec review of the Shadow bot.

Q8 — Supply-chain: hash-pin Python dependencies

  • requirements.txt is now fully hash-pinned across the transitive tree (generated via pip-compile --generate-hashes); top-level pins live in the new requirements.in.
  • Both workflow jobs (analyze, act) now install with pip install --require-hashes, so a tampered/substituted PyPI artifact fails the install instead of executing.
  • Verified: --require-hashes install succeeds in a clean venv; requests/boto3/PyYAML import at pinned versions (12 packages, 166 hashes).

Q10 — Monitoring: behavioral anomaly alarms

The engine already emitted CloudWatch metrics (namespace Shadow) but had no alarms. Adds (opt-in, gated on BudgetEmailAddress — no new parameter):

  • ShadowAlarmTopic (SNS, email-subscribed)
  • ShadowEscalationSpikeAlarm — Escalations Sum > 25/hr (possible prompt-injection/abuse burst or systemic bail)
  • ShadowInvocationSpikeAlarm — Invocations Sum > 100/hr (public-trigger flood / cost abuse, faster signal than the monthly Budget)
  • CFN contract test updated in lockstep for the new resource keys.

Note on approvals: there is no per-run "approval" metric because auto-approval is a separate adopter-side workflow, not the engine — and it's now off-by-default (see the per-repo SHADOW_AUTO_APPROVE gate PRs). Escalation/invocation spikes are the engine-level anomaly signals.

541 tests pass. Touches .github/ → requires human approval + merge.

Q10 (AppSec review): add optional fleet-wide anomaly alarms, provisioned by the
CFN Launch Stack when BudgetEmailAddress is set (off otherwise). Two alarms —
escalation spike (default 25/hr) and invocation spike (default 100/hr), tunable
via new parameters — plus an SNS topic. Each alarm aggregates its metric across
all dimension schemas with a Metrics Insights query (SELECT SUM(...) FROM
"Shadow"): a fixed-dimension alarm would watch an empty stream, and SEARCH is
illegal in alarms. Alarms are regional and depend on Shadow's metric emission,
both documented. Contract test asserts each alarm aggregates an emitted metric
and wires its own threshold param.

Q8 (AppSec review): keep deps version-pinned, not hash-pinned — SHA-pinned
actions are the required control; pip hash-pinning was disproportionate for 3
deps (recipe noted for future).

Docs: README cost-protection/monitoring updated for the alarms (region + metric
dependencies, honest cost framing) and a corrected email-only budget row;
cloudwatch.py docstring notes the Reason dimension.

542 tests pass.
@sudsali
sudsali force-pushed the appsec/hardening-q8-q10 branch from 08126dc to 341b021 Compare July 21, 2026 01:08
@sudsali
sudsali merged commit 3a9e9dd into main Jul 21, 2026
3 checks passed
@sudsali
sudsali deleted the appsec/hardening-q8-q10 branch July 21, 2026 01:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant