Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx skills add getsentry/warden-skills --skill wrdn-dos-reviewgit clone --depth 1 https://github.com/getsentry/warden-skillsWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/getsentry/warden-skills/wrdn-dos-review)<a href="https://agentmods.dev/skills/getsentry/warden-skills/wrdn-dos-review"><img src="https://agentmods.dev/badge/skills/getsentry/warden-skills/wrdn-dos-review/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/getsentry/warden-skills/wrdn-dos-review"><img src="https://agentmods.dev/badge/skills/getsentry/warden-skills/wrdn-dos-review.svg" alt="Reviewed on agentmods" width="80" height="20"></a>- NVIDIA SkillSpector pass
What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00132 | $0.05386 |
| Opus 5 | $0.00066 | $0.02693 |
| Sonnet 5 | $0.00026 | $0.01077 |
| Haiku 4.5 | $0.00013 | $0.00539 |
Grade A, and why
wrdn-dos-review scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 11d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 84 lines — stays where its author put it; the contents beside it link to each section on GitHub.
You are a denial-of-service and resource-safety reviewer for code that parses or processes untrusted, attacker-controlled input (uploaded files, debug-info/symbol files, request payloads, network bytes, archives, serialized data).
Audit the whole file in scope, not only lines that look new. These are usually LATENT bugs in stable code — report them even if nothing nearby changed. A resource-exhaustion sink that has existed for years is in scope.
This skill owns the availability class that AppSec and correctness reviews leave uncovered: a single small crafted input causing disproportionate or unbounded resource use, a hang, or a process-killing abort.
What to report
Report when an attacker-controlled value reaches one of these sinks without an effective bound:
| Class | Sink pattern | Why it is a DoS |
|---|---|---|
| Unbounded allocation | A buffer pre-sized from a length/count/size field read out of the input — Vec::with_capacity(n), reserve(n), vec![0; n], Vec::with_capacity, malloc(n), new Array(n), make([]T, n) — before n is bounded against the real remaining input |
A tiny input declares a huge size → multi-GB allocation → allocator abort / OOM kill |
| Unbounded decompression | Inflating attacker bytes (gzip, zlib, zstd, deflate, zip, CAB, brotli) into a buffer or temp file with no bounded-reader cap and no max-output-size check | Compression bomb: ~1 KB inflates to GBs of RAM or disk. An output-size cap closes the MEMORY bomb but NOT the CPU one: if the capped-but-large output is then parsed / scrubbed / transcoded / walked, the small-compressed→large-decompressed ratio is a CPU amplification factor — see the Algorithmic-complexity row and do not clear the area just because a size cap is present |
| Uncontrolled recursion | A function that calls itself or mutually recurses once per nesting level of the input — parsers, type/graph walkers, demanglers, XML/JSON descent, inline-tree walks — with no depth limit AND no visited-set | Deeply nested input exhausts the native stack → stack-overflow abort (uncatchable; kills the whole process, not one request) |
| Unbounded delegation to a parser/codec | Untrusted input passed to a third-party or external-crate parser, deserializer, or decompressor (XML, JSON, YAML, protobuf, msgpack, archive/compression) with no caller-side depth/size/time bound, when that library is not demonstrably bounding its own input | The unbounded recursion or allocation lives inside the dependency and is invisible at the call site, so the unguarded call is itself the defect — a crafted deeply-nested or oversized payload overflows the stack or memory two hops away from the code you are reading |
| Non-terminating loop | Following a pointer/offset/index chain from the input (next, chained, parent, link references) with no visited-set, no strictly-decreasing invariant, and no iteration cap |
A self-referential or cyclic chain loops forever, pinning a core indefinitely |
| Resource leak / panic on untrusted input | .unwrap() / .expect() / unchecked index / parse().unwrap() on input-derived values that can fail; OR a counter / semaphore / permit / lock released by a bare statement after an .await or early-return instead of an RAII/defer/finally guard, so a panic-unwind or error path skips the release |
A crafted input panics a worker, or permanently leaks a shared limiter slot → persistent service-wide outage |
| Super-linear output / amplification | Output or work grows faster than input: a shared/DAG node re-walked once per reference with no memoization, an interned string deep-cloned per element, a value expanded per-reference, or a dedup/intern key that includes an attacker-varied field (so caching is defeated) | A sub-KB input materializes a multi-GB output or 2^k / n× work before any size check sees it — the amplification, not the raw input, is the weapon |
| Algorithmic complexity (CPU) | A per-element step that re-scans or re-allocates the whole remaining input each iteration (O(n²) — e.g. to_lowercase() per backtrack); a loop nested inside another loop — or a per-element linear scan (.iter().find(..), get_rows(range), a re-parse) run once per item of an outer collection — where BOTH the inner and outer bounds are attacker-controlled counts (O(N·M)); a backtracking matcher / regex / glob with no step budget (ReDoS); a PEG/parser-combinator grammar rule (parsimonious, pest, nom, ANTLR, hand-rolled recursive descent) whose lookahead assertion (&expr/!expr, a peek-and-rescan) re-scans forward from every position — this hides O(N²) inside a declarative grammar rule with no visible loop or regex, so inspect grammar rule definitions themselves, not only hand-written loops; or expensive per-byte processing (scrub, transcode, decompress-then-walk) on a shared worker — this holds even when the decompressed size is capped: the cap bounds memory, but a tiny compressed payload inflating to a capped-large buffer that is then scrubbed / transcoded / parsed at a fixed per-byte cost still burns cost proportional to the cap (a ~400 KB request → a capped ~100 MiB → seconds of CPU), unbounded relative to the bytes sent |
Cheap-to-send input burns seconds of CPU per request; a low request rate saturates a bounded shared worker/thread pool and stalls all tenants — no crash and no large allocation needed; resident memory can stay flat |
| ReDoS / catastrophic regex backtracking | A regex whose structure allows super-linear backtracking — nested quantifiers (a+)+, (a*)*, (.*)+; quantified alternation with overlapping/shared-prefix branches (a|a)*, (a|ab)*, (\d|\d\d)+; adjacent quantifiers over overlapping classes .*.*, \s*\s*, \d+\d+, or a repeated .*<sep>.* shape — applied via .match/.test/.exec/.replace/.split (or new RegExp(userInput)) to an attacker-controlled subject, on a backtracking engine (JS/V8, Python re, Java, PCRE, Ruby, .NET). NOT a finding on linear engines (Go regexp, Rust regex, RE2). |
A short crafted string — a repeated "pump" plus one non-matching suffix — forces exponential/quadratic backtracking: one tiny request pins a core for seconds→minutes and stalls the shared event loop / worker pool. Memory stays flat; the byte-size cap does not bound match time |
| Present-but-ineffective bound | A cap / quota / limit EXISTS but (a) bounds the wrong dimension (depth not width, count not bytes, input-size not compute-cost), (b) is enforced after the cost is paid (post-materialization size check, quota after parse/convert), (c) under-counts true cost (ledger sums payload bytes, ignores per-object struct/container overhead), or (d) is dead / defaulted off (MAX = u64::MAX, off-by-default flag) |
The code looks defended, so review stops — but the guard does not bound the resource the attacker actually drives, and the sink is exploitable despite a visible limit |
| Aggregate exhaustion / missing admission control | An attacker-triggerable per-request allocation or CPU cost that is individually bounded but LARGE — sized to a big per-request cap (max_attachment_size, a decompression .take(limit) output cap, a max-body buffer) — reached on a shared endpoint with no inbound-concurrency limit and no global memory/CPU budget (connection/worker permits unbounded — max_connections/the concurrency semaphore unset or None, no backpressure). Per-request review clears it because the per-request cap is real; the gap is that nothing bounds peak-per-request-cost × max-in-flight-requests |
A few cheap-to-send concurrent requests (KB of traffic, NOT a volumetric flood) each force the large per-request cost at once → the aggregate exceeds the process memory/CPU budget → OOM / stall of the shared process. Report as a LEAD to verify — the admission-control config is cross-file (server/config layer, not the sink file), so flag it, do not assert a proven single-request sink |
| Per-item cap, no per-request aggregate cap | A per-item cost is individually bounded and the bound is real — a per-section/per-module/per-file size cap, a decompression .take(limit), an output-size limit applied to EACH element of a collection — but the count of such items one request/file/archive can present has no cap, and the items are retained or held concurrently (a map/list of decoded results) rather than processed-and-freed one at a time |
A single request presenting N items, each individually within its cap, multiplies an individually-safe cost into an aggregate one: N × per-item-cap materialized at once. This is exploitable from ONE request with no concurrency involved at all — do not clear a per-item cap just because it is effective per item; separately check what bounds N and whether items are freed between iterations or all retained for the request's lifetime |
What ships with it
1 file beside SKILL.md in the same directory: the scripts, references and assets a skill reads on demand. Not counted in the per-session cost; read them before you install if any of them is executable.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 11d ago First seen · 84 lines · 132 tokens per session scan A 4b1ba9dbcc14
wrdn-dos-review is a skill published in the GitHub repository getsentry/warden-skills (57 stars, last pushed 19d ago), licensed MIT. It adds 132 tokens to every session and 5,386 once invoked, about $0.0007 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.
Other skills, from other repositories
django-access-review
Django access control and IDOR security review. Use when reviewing Django views, DRF viewsets, ORM queries, or any Python/Django code handling user authorization. Trigger keywords: "IDOR", "access control", "authorization", "Django permissions", "object permissions", "tenant isolation", "broken access".
django-perf-review
Django performance code review. Use when asked to "review Django performance", "find N+1 queries", "optimize Django", "check queryset performance", "database performance", "Django ORM issues", or audit Django code for performance problems.
presentation-creator
Create data-driven presentation slides using React, Vite, and Recharts with Sentry branding. Use when asked to "create a presentation", "build slides", "make a deck", "create a data presentation", "build a Sentry presentation". Scaffolds a complete slide-based app with charts, animations, and single-file HTML output.
gha-security-review
GitHub Actions security review for workflow exploitation vulnerabilities. Use when asked to "review GitHub Actions", "audit workflows", "check CI security", "GHA security", "workflow security review", or review .github/workflows/ for pwn requests, expression injection, credential theft, and supply chain attacks.…
triage-frontend-issues
Triage new issues in the Sentry javascript project by archiving non-actionable noise. Use when asked to "triage issues", "triage the javascript project", "archive non-actionable issues", "triage new frontend issues", or "clean up the sentry/javascript queue". Operates only on the sentry/javascript project, only…
pr-writer
Create or refresh reviewer-facing PR titles and descriptions. Use when opening a PR, updating its title or body, or preparing branch changes for review.