skip to content

Your build shades a JSON parser into your own namespace — how do you keep it visible in your SBOM?

level: seniorimportance: should knowfreq 44%

answer

  1. the coordinate disappears from the consumer's graph
  2. relocation rewrites bytes, so hashes miss too
  3. present, exploitable, unnameable
  4. capture identity where the build still knows it
  5. you became its supplier downstream

basics

~20 s

Generate the SBOM from the resolved dependency graph at build time, before relocation erases the coordinates, and ship it with the artifact. Once classes are relocated into your namespace, no consumer can recover the parser's identity by inspecting what you published.

solid answer

~40 s

Shading bundles a dependency's classes into your artifact and rewrites their package names, so two identities vanish at once: the parser no longer appears in any consumer's resolved dependency graph, and because relocation rewrites the bytes, the shipped class no longer hashes to anything upstream published. The component is present and just as exploitable, but unnameable — a silent miss, which is worse than noise. The control has to run where the information still exists: emit the SBOM from the build's resolved graph, record each relocated dependency by its original purl, and attach that document to the published artifact, because consumers cannot reconstruct it by scanning. Be honest about the second half too: you are now the supplier of that parser to everyone downstream, and patching it is your job.

go deeper

for a junior

Know what shading is: a dependency's classes are copied into your artifact under renamed packages. Be able to say that the code is still there even though the dependency name is gone.

for a middle

Explain why both identifiers fail at once — the coordinate leaves the consumer's resolved graph, and relocation rewrites the bytes so the hash no longer matches upstream.

for a senior

Show where you would place the control: SBOM generation from the resolved graph inside the build, the original coordinate recorded per relocated component, and the document attached to the published artifact.

for a principal

Own the consequence that shading makes you the supplier of what you embedded, and set the policy for when it is allowed, who watches the embedded components, and what release cadence you owe consumers who cannot patch it themselves.

## What shading does to identity Shading — also called relocation — takes a dependency's compiled classes, rewrites their package names into a namespace you control, and bundles the result inside your own artifact. It is done for a good reason: it lets you pin a version of a library without forcing that version on everybody who consumes you, which is the standard escape from diamond version conflicts. The security consequence is rarely considered at the same time. After shading, three things are true at once: 1. **The consumer's dependency graph does not contain the parser.** They depend on your artifact. Nothing in the coordinates they resolve mentions the library you embedded, so any inventory built from resolved dependencies — which is how most inventories are built — is simply blind to it. 2. **The bytes changed, so hashes do not help either.** Relocation rewrites the package name inside every class, which changes the file. A hash of the shipped class matches nothing the original publisher ever produced. The one identifier that is normally beyond argument has been invalidated by a routine build step. 3. **The vulnerable code is still there and still reachable.** Nothing about relocation removes a defect. If the parser mishandles deeply nested input, your artifact mishandles deeply nested input, under a different class name. That combination — present, exploitable, unnameable — is the worst shape a supply-chain problem can take. A false positive costs an engineer an hour. This costs you the knowledge that you have a problem at all. ## Where the information still exists The only moment at which the parser's identity is unambiguous is **inside the build, before or alongside relocation**. At that point the build has resolved the dependency, it knows the ecosystem, the coordinates and the version, and it can compute an exact purl. Every viable control follows from that: - **Generate the SBOM from the resolved dependency graph, not from the finished archive.** An inventory derived from the shipped artifact has already lost the data; one derived from the graph has it. - **Record the original coordinate of every relocated dependency**, and where the format supports it, record the relationship as well — CycloneDX has a `pedigree` structure for ancestry, variants and applied patches, and SPDX can express derivation through relationships. "This component is a relocated copy of that one" is a fact worth persisting. - **Ship the SBOM with the artifact**, attached to the published package rather than left in a build directory. Your consumers cannot recover this by scanning, so if you do not hand it over it does not exist for them. ## What a consumer can do without it Not much, and it is worth being able to say so plainly. Scanning a fat archive for embedded components relies on similarity heuristics: matching class or symbol layouts, embedded resource files, version constants left in string tables. These are genuinely useful and genuinely best-effort — they produce both misses and confident wrong answers, and they degrade further when relocation also strips metadata. A consumer's realistic options are to demand an SBOM from you, to treat your artifact as an opaque component supplied by you, or to reimplement your build. Only the first is reasonable. ## The obligation that comes with it The part candidates most often miss is the responsibility transfer. Once you shade a library into your artifact, **you are its supplier for every downstream consumer**. They cannot upgrade it; the version is welded into your release. When a defect is published against that library, they cannot act — only you can, by rebuilding and republishing. That has three practical consequences: - The embedded component must be in **your** watch list, with an owner, because nobody downstream is watching it on your behalf. - Your release cadence becomes their patch latency. If you ship quarterly, your consumers wait a quarter. - "We shade it, so we are not affected" is exactly backwards and is worth catching in review: shading changes the name, not the code. ## The same failure without shading The pattern repeats wherever a build changes a component's name. An internal fork of a module published under your own module path never matches upstream and never will, no matter how faithfully you rebase it. Vendored source copied into a repository has no coordinate at all. A statically linked native library disappears into an executable. In every case the answer has the same shape: capture identity at the moment the build still knows it, record the derivation explicitly, and accept that you are now the supplier of what you absorbed.

  • An internal fork keeps its own module path forever. Is that the same problem?
    It is the same identity break with a different cause. The fork's coordinate is legitimate and permanent, so it will never match upstream by name, and no amount of rebasing changes that. Handle it by recording the upstream lineage as an explicit derived-from relationship in the inventory and assigning an owner who tracks upstream on the fork's behalf. The mistake is assuming a fork inherits upstream's attention automatically.
  • A consumer only has your published archive. What can they actually determine?
    Only what similarity heuristics give them: class and symbol layouts, embedded resources, version strings left in the binary. That is best-effort and produces both misses and confident wrong answers, particularly once relocation has rewritten names. Their honest position is to record your artifact as an opaque component supplied by you and to require an SBOM from you as a condition of consuming it.
  • Does signing the shipped artifact help here?
    No, and the confusion is worth naming. A signature says who vouches for the artifact; an SBOM says what is inside it. A perfectly signed fat archive with a relocated parser inside is exactly as unnameable as an unsigned one. Signing and inventory answer different questions, and neither substitutes for the other.
  • How would you catch a new shading step being introduced?
    Diff the build-time inventory across releases, not just the source. A relocation added in a build configuration shows up as a component that vanishes from the shipped artifact's component list while the resolved graph still contains it, and as a sudden drop in component count. Making that diff part of the release review turns an invisible change into a visible one.

Rebinding someone else's chapters into your own book with the chapter titles rewritten. The text is still there and still says what it said, but nobody searching the original titles will ever find it in your library.

saying these in an interview costs you the question

  • Says shading removes the vulnerability along with the name
  • Expects a consumer to scan the fat archive and find it
  • Believes a file hash still matches after relocation
  • Generates the SBOM from the published artifact instead of the build
  • Assumes downstream consumers can upgrade the embedded library

context