taxonomy · how systems fail
Patterns.
Named bug-classes and conceptual frames. Each pattern is its own meta-analysis. The mechanism that gets named, plus every post that exhibits it.
- Design Debt Driver0173 postsDesign Debt Driver
A component whose bug-class keeps recurring. Patches address symptoms; the design holds the primitive.
- Unpatchable Primitive0228 postsUnpatchable Primitive
The bug class is too fundamental to the design. Patches close instances; the primitive remains.
- Content Is Command0322 postsContent Is Command
External content feeds an interpreter that treats it as instructions. Prompt injection is one instance.
- Internal Only By Convention0421 postsunmappedInternal Only By Convention
A header, query parameter, or environment input the framework defines as internal-IPC-only, read with security-relevant authority on every inbound network request. The "internal-only" contract is documentation, not enforcement.
- Trust Inversion0520 postsTrust Inversion
The tools and credentials that authorize access to your systems are now the attack surface.
- Parallel Implementation Gap0616 postsunmappedParallel Implementation Gap
A capability is implemented by two or more parallel modules (per adapter, per runtime, per deployment target). The canonical module imports a security check from a shared utility and enforces it; a divergent module, written separately for a different environment, never imports it. Both expose the same client-facing contract; one is gated, the other is not. The CVE names the divergent module.
- The Detector Is The Target0715 postsThe Detector Is The Target
The sandbox, scanner, or SOC tool is itself the attack surface.
- Unauth Write To Execution Path0814 postsUnauth Write To Execution Path
No auth required to write a file into a path the server executes. Webroot upload, CGI drop, etc.
- Disclosure After Exploitation0911 postsDisclosure After Exploitation
Vendor discloses only after active in-wild exploitation. The gap between first-seen and CVE is the story.
- Gate Before Canonicalize1011 postsunmappedGate Before Canonicalize
A security check inspects an input for a forbidden form. A downstream subsystem canonicalizes the same input (URL decoding, path-parameter stripping, Unicode normalization, escape resolution) into that forbidden form. The check sees the wrapped representation; the action sees the unwrapped one. The fix is to canonicalize before checking, never after.
- Todo That Shipped1111 postsTodo That Shipped
The fix was in a comment. The code shipped without it. Audit your oldest TODOs.
- Security Tool As Primitive129 postsSecurity Tool As Primitive
The privileged action of your security tool becomes the attack. Defender's hands become attacker's hands.
- Fail Open Intercept138 postsFail Open Intercept
Security gate can't decrypt/validate a message and forwards it anyway. Logs the failure, does the action.
- Disclaimer Wrapped Campaign Kit147 postsDisclaimer Wrapped Campaign Kit
A PoC that ships a full weaponizer behind a 'for authorized testing only' disclaimer.
- Emergent Primitive155 postsEmergent Primitive
Individually safe components that compose into an attack. Nobody owns the intersection.
- Nonce Is Not Auth165 postsNonce Is Not Auth
CSRF tokens mistaken for authentication. Valid nonce does not equal authenticated caller.
- Placeholder PoC175 postsunmappedPlaceholder PoC
An exploit script published against an existing CVE, structured as a working exploit but with one or more critical parameters marked as placeholders the user must adjust. The author lacks the underlying primitive; the artifact attaches authorship to a CVE-shaped wrapper rather than to a working exploit. A scanner polling GitHub for CVE-named repositories registers it as "PoC available"; the script's own comments confirm the registration is wrong.
- Caller Chosen Key184 postsunmappedCaller Chosen Key
A server signs a bearer token with a key the caller provides on the request, then accepts that same caller-supplied key on verification. The signature binds only that the caller could ask for issuance, not that they held any credential.
- Denial By Pedantry194 postsDenial By Pedantry
'We weren't breached' via a narrow reading of their own terms. Non-denial denial.
- Middleware Outside The Hijacker204 postsunmappedMiddleware Outside The Hijacker
Request-scoped middleware (auth, rate limit, RBAC) is wrapped around a handler that upgrades a single request into a long-lived connection. The middleware authenticates the handshake, then never sees the streams that follow.
- Name Is The Only Type214 postsunmappedName Is The Only Type
A field stored as a generic map (interface{}, JSON, dict) whose conventional name implies a constrained shape (an ID, a path, a number). The producer's contract is implicit in the name; once an API exposes write access, the consumer reads attacker input where it expected server output.
- Hash Is Not Entropy223 postsunmappedHash Is Not Entropy
A security token is derived by running a cryptographic hash over a low-entropy value (a timestamp, a counter, a username, an autoincrement primary key). The cryptographic strength of the hash function is treated as compensating for the predictability of the input. It does not. The hash is a deterministic function; the output's entropy is bounded by the input's entropy, regardless of how the bits are spread across the digest.
- Idle Indistinguishable From Broken233 postsIdle Indistinguishable From Broken
A periodic process that emits identical success telemetry for "I checked and there was nothing to do" and "I checked and could not determine what to do." Observers cannot tell health from breakage; risk accumulates silently.
- Maintainer Account Compromise243 postsMaintainer Account Compromise
Single maintainer account gates publishes to millions. One compromise ships to every downstream.
- Mutable Reference As Immutable253 postsMutable Reference As Immutable
Git tags, date-labeled artifacts, the latest tag. Treated as pinned. Not.
- Paywall PoC263 postsunmappedPaywall PoC
A high-severity CVE under remediation deadline pressure attracts a throwaway GitHub account that publishes a detailed README describing an exploit. The repository contains no exploit code; the file is gated behind a no-refunds crypto paywall. The asset being sold is the defender's urgency, not a working primitive.
- Revocation Gap273 postsRevocation Gap
The window between credential compromise and detection. Every action in that window is legitimate.
- Sanitized The Secrets, Not The Sink283 postsunmappedSanitized The Secrets, Not The Sink
A function applies escape/quote/sanitize logic to user-controlled fields the developer perceives as security-sensitive (credentials, passwords, tokens) and omits it on a field that actually flows into the dangerous interpreter (shell, SQL, format string, eval). The mitigation logic in the same function is proof the developer understood the threat; the unsanitized field is proof they sorted by perceived field sensitivity rather than by destination.
- Unmitigated Binary293 postsunmappedUnmitigated Binary
A binary compiled without the standard exploit mitigations (PIE, stack canary, FORTIFY_SOURCE, full RELRO). Every memory-safety bug becomes RCE because the build, not the source, decides exploitability.
- Allowlist Grain Is The Method302 postsunmappedAllowlist Grain Is The Method
An interpreter sandbox enforces a method allowlist by class and method name. One allow-listed method's return value carries data from a higher trust tier than the allowlist's grain can see. The allowlist filtered at the method level; the security boundary lives at the data level.
- Borrowed Pages As Scratch312 postsunmappedBorrowed Pages As Scratch
A subsystem performs fixed-size scratch writes into a destination buffer under an internal contract that it owns the memory. Another subsystem supplies that buffer with foreign-owned pages (page cache, mapped device, peer process). The contract is documentation; the legitimate scratch becomes a write primitive across a trust boundary nobody guards.
- Commented Out Code Is Testimony322 postsCommented Out Code Is Testimony
The capability the researcher didn't ship tells you what the capability is. Read what's commented out.
- Existence Is Authorization332 postsunmappedExistence Is Authorization
A handler given a caller-supplied identifier checks that the named resource exists and treats the existence check as the authorization decision. The identifier is enumerable; the resource carries no per-call credential. Anyone who can guess or enumerate the identifier becomes the authorized caller.
- Extension As Mitigation342 postsunmappedExtension As Mitigation
A library exposes a subclass, callback, or hook framed in the documentation as the seam where the consumer adds security validation, while keeping the unsafe sinks inside the library and never enumerating the inputs the consumer must sanitize. The extension is positioned as the fix; using it does not close the gap.
- MFT as Primary Target352 postsMFT as Primary Target
Managed file transfer products carry the payload and the trust. Now carry the breaches.
- Persistent Blindspot362 postsPersistent Blindspot
The attack does not steal. It makes the defender permanently blind to a class of events.
- Phantom Project Documentation372 postsunmappedPhantom Project Documentation
A repository whose documentation describes a project layout — file names, command-line flags, release history, build instructions — that does not match what the repository contains. Each artifact is internally consistent because each was generated from a separate prompt; no artifact references the others because no prompt asked the model to make them coherent. A scanner that polls GitHub for CVE-numbered repositories registers the documentation as evidence of a PoC; the directory listing the documentation describes does not exist on disk.
- Predicate Stringifies The Object382 postsunmappedPredicate Stringifies The Object
A security predicate intends to test one field of a structured value (a path, a header, a claim) but is implemented against the value's stringified form. The string representation includes other attacker-controlled fields, and the substring or equality check accepts the gate's allow-string from any of them.
- Security Metric Theater392 postsSecurity Metric Theater
Coverage reported as a fraction when only the numerator was ever the story. MFA %, EDR coverage, etc.
- Self Propagating Supply Chain402 postsSelf Propagating Supply Chain
Worm pattern in a package registry: infected package harvests credentials, publishes to the next.
- Setting Was Advisory412 postsunmappedSetting Was Advisory
A library accepts a security-relevant flag from its caller and overrides it inside a wrapper layer when the underlying framework's safe response to the caller's setting returns a generic fallback type. The library re-invokes the framework with the flag inverted. No log, exception, or callback informs the caller. The flag has the API surface of an enforced control and the runtime behavior of a hint.
- The Shell Was Not The Sink422 postsunmappedThe Shell Was Not The Sink
A sanitization function is named, implemented, and documented for one interpreter (the POSIX shell, an HTML renderer, a SQL dialect) and applied uniformly to inputs that flow into a different interpreter with different parsing rules. The quote-wrap survives the named sink intact, then is fed via pipe, stdin, embedded call, or template into the actual sink, which sees a literal character the wrap was not designed to neutralise. The function's name encodes the threat model the developer was thinking about; the destination encodes the one they were not.
- Theatrical Reissue432 postsunmappedTheatrical Reissue
An existing CVE and an existing working PoC are republished by a separate author with mathematical-sounding pseudoscience added to the loop structure (Riemann zeros, "temporal" modifiers, exotic decay constants), claiming a severity upgrade the underlying bug cannot support. The added math is decorative. In many cases the headlining script does not reach the original exploit primitive because the author replaced the working network call with a print statement.
- Validated Source, Not Destination442 postsunmappedValidated Source, Not Destination
A file upload handler validates the source filename's extension and writes the file under a destination basename the caller supplied separately. Validating one filename does not validate the other.
- Aliased Carrier Bypass451 postunmappedAliased Carrier Bypass
A dispatcher reads from a preference chain of aliased input carriers (e.g., `json` then `msg` then a raw envelope). A sanitizing gate covers one alias and not the others. The dispatcher's first-preferred carrier is the bypass, and the gate's own scope, named after the field the original PoC happened to use, is the admission.
- Auth Pins The Slot, Not The Value461 postAuth Pins The Slot, Not The Value
Authorization is granted for a request-handle whose contents the attacker can replace before the grant is consumed. Polkit, OAuth, transaction caches, any framework where auth is requested for a slot and the slot's value is mutable post-request.
- Backport Gap471 postunmappedBackport Gap
A coordinated multi-branch release ships a security fix on one branch and ships the unfixed code on the others. The CVE record covers all branches; the patch covered the one.
- Channel Bounded Disclosure481 postunmappedChannel Bounded Disclosure
A memory or data disclosure primitive whose exfiltration path passes through a destructive transform (quantization, compression, hashing, sampling). The primitive accesses the bytes; the channel sets the ceiling on what the attacker recovers, often well below the rated severity.
- Closed Network Assumed491 postunmappedClosed Network Assumed
A parser written for a "trusted" bus (CAN, internal IPC, on-prem VLAN) accepts framing fields as if the protocol's valid-range constraints were guaranteed by the medium. Sequence numbers, length fields, and indices arrive without bounds checks because the developer's threat model excludes adversaries on the wire. When the bus admits a malformed frame, the protocol-derived constant becomes the size of the overflow.
- Coursework PoC501 postunmappedCoursework PoC
A CVE-numbered GitHub repository whose contents are educational coursework (a class presentation, lab report, or writeup) described in prose and built with presentation frameworks rather than implemented as runnable code. The students chose the CVE as their assignment topic; the repository name carries the CVE identifier because the project's subject does. A scanner that indexes GitHub by CVE-numbered repository name registers the coursework as a published PoC; the artifact never claimed to be one.
- Debug Flag Left On511 postunmappedDebug Flag Left On
A compile-time feature flag named with a debug convention (`_DEBUG_*`, `_IOCTL_DEBUG_*`, `_DBG_*`) gates a security-relevant capability and is unconditionally `#define`d in production headers. No `#ifdef DEBUG` or build-system mechanism enforces the convention. The vendor's release discipline is to comment the macro out before shipping; the discipline is applied to adjacent macros and not to this one. The "debug only" contract has two manifestations in the codebase, the macro's name and an inline comment admitting what it does. The runtime sees neither.
- Duplicate Chunk Reinit521 postunmappedDuplicate Chunk Reinit
A multi-part or container-format parser handles a second occurrence of a stream-defining chunk by re-initializing its per-stream state in place. The re-init releases the first occurrence's allocations as a side effect; an outer wrapper that owns the lifecycle retains pointers to those allocations and reaches them at teardown.
- Empty Filter Is Wildcard531 postunmappedEmpty Filter Is Wildcard
An API treats an empty filter argument as 'no filter applied' and returns the full set rather than the empty set or an error. A consumer that funnels attacker-controlled input into the filter without rejecting empty values converts an exact-match query into a wildcard scan.
- Fix Reads The Bug541 postunmappedFix Reads The Bug
A patch implements a security control whose enforcement requires the same observation the bug exposes. Closing the channel would prevent the control from working, so the channel stays open by design and the mitigation rate-limits or post-processes readings of it.
- Frame Bounds Headers Only551 postunmappedFrame Bounds Headers Only
A parser checks the outer length field that frames its iteration, then trusts each inner length field to drive writes without checking it against the same frame.
- Host Header As Self561 postunmappedHost Header As Self
A server validates signed inbound messages against its own URL and derives that URL from client-supplied request headers. The signed 'intended for X' check becomes 'intended for whatever the client claims X is.'
- Junction Preemption571 postJunction Preemption
A privileged process writes to a directory it never pre-created with restrictive permissions. A standard user occupies the path first as an NTFS junction. The privileged write follows the attacker's redirection.
- Null Equals Null581 postunmappedNull Equals Null
A multi-tenant authorization check encoded as Python equality between two fields that can both legitimately be the unset sentinel (None, null, empty string). When both sides are unset, the equality returns true and the check waves the caller through. The sentinel that means "no tenant" becomes the membership of a shared default tenant, usually the largest population on the system. The fix is never raw equality, the comparison must explicitly assert that the value is non-null before allowing a match.
- Object Literal As Map591 postunmappedObject Literal As Map
JavaScript code uses a plain object literal `{}` as a string-keyed dictionary against attacker-controlled keys. Plain objects inherit twelve keys from `Object.prototype`; every one of them resolves to a non-undefined inherited value through bracket lookup. Names like `__proto__`, `hasOwnProperty`, and `toString` reach those values without writing anything to the prototype. The default container leaks the prototype chain. `Object.create(null)` and `Map` do not.
- Out Of Band, Also In Band601 postunmappedOut Of Band, Also In Band
A flow whose security depends on the secret traveling only over a trusted side channel (email, SMS, push) is implemented by a service function that hands the same mutable object to the side-channel sender and to the in-band HTTP response. The "out of band only" promise collapses into "out of band, also in band."
- Pool Retains Prior Writes611 postunmappedPool Retains Prior Writes
A kernel object pool returns entries to a freelist without erasing them. Each caller's writes past the next caller's expected watermark persist into entries handed to subsequent unrelated callers. The cross-caller contract is that nobody reads past their own writes; the kernel does not enforce it. Combined with any bounded out-of-bounds write into a pool entry, the residue from an attacker's earlier exec becomes a persistent attacker-controlled staging area in another process's view of the pool.
- Prefix Is Not Identity621 postunmappedPrefix Is Not Identity
A cache or dedup key derived from a fixed-length prefix of a value, on an implicit assumption that the prefix carries per-actor entropy. When the producer's encoding concentrates entropy past the prefix window (a JWT payload past the header, a URL path past the host, a salted hash past the salt), every actor's value maps to one bucket. The type signature is `str`; the entropy contract is documentation. When the producer's shape drifts, the slice goes from fingerprint to constant without warning.
- Prototype Pollution Trust Bypass631 postPrototype Pollution Trust Bypass
A trust check that reads shared prototype state. Attacker writes once, every object reports trusted.
- Rejection Echoes The Secret641 postunmappedRejection Echoes The Secret
An auth or authz check that fails the caller, then writes the expected value into the response body before terminating. The reject branch performs the comparison, computes the value the caller should have sent, and emits it. Often originates as a debug print added during initial development to verify the comparison works; ships because the reject branch is the path no developer re-reads.
- Safe Mode Was Opt In651 postunmappedSafe Mode Was Opt In
A library exposes sanitization as opt-in flags with unsafe defaults. A caller wiring the library's output into a sink that interprets the result as code (raw HTML, SQL, shell) accepts the unsafe defaults by reaching for the library's static or factory helper instead of constructing the instance and setting the flags. The flags exist in the library; the fix is to set them.
- Signed But Unextracted661 postunmappedSigned But Unextracted
A document arrives with a cryptographic signature over an inner artifact, but the verifier extracts signatures at a pipeline stage where the inner artifact is still wrapped (encrypted, encoded, deferred-parsed). After a later stage opens the wrapper, the verifier never re-extracts. The signature exists in the document and is never in the validator's working set; the outer envelope's signature is treated as having authenticated content it never covered.
- Signing Surface Poisoning671 postSigning Surface Poisoning
Hardware wallet / HSM / signer shows one thing, signs another. Trust boundary lives at the rendering layer.
- Source Grep Is Not A Sandbox681 postunmappedSource Grep Is Not A Sandbox
A security check that scans the source text of code for forbidden tokens before handing the code to a dynamic interpreter. The interpreter resolves names, computes strings, traverses method dispatch, and rewrites bytecode at runtime, so any token the check forbids can be reconstructed from pieces the check never matched. The blocklist becomes documentation of the author's threat model rather than enforcement of it.
- TOCTOU That Isn't691 postTOCTOU That Isn't
A 'race condition' that's actually deterministic. Attacker controls timing because the other side hasn't run yet.
- Unsigned Ecosystem Echo701 postUnsigned Ecosystem Echo
A new ecosystem replaying every lesson the old ones learned. Same registry shape, same provenance gap.
- Validated At Boot711 postunmappedValidated At Boot
A security-relevant configuration is validated once at process startup and never re-checked, even though the same process supports hot-reload, dynamic registration, or runtime mutation of that same configuration. The startup pass creates an assurance the runtime path does not maintain. The rail ran. The state changed. The runtime never reconciles.