Claude Code shipped version 2.1.277 on September 18, 2026. Buried in a long changelog entry are three related changes that all target the same problem: text that arrives from somewhere other than the user, but that the model could previously mistake for the user's own instructions. Per the official changelog, under version 2.1.277:
Changed subagent results to reach the main agent under a header marking them as subagent output, with the result indented, so text in a subagent's result cannot pass as the session's own instructions
Changed workflow scripts' computed
agent()prompts on Bedrock, Vertex and Foundry to reach the subagent framed as script-authored text, so the safety classifier does not read them as the user
Improved prompt handling: invisible Unicode formatting and tag characters in a prompt are removed and the cleaned prompt is shown for review before it is sent
Three different code paths, one shared failure mode: something other than the person at the keyboard puts text in front of the model, and without a clear boundary, the model has no way to tell that text apart from an instruction it should obey.
What each change actually closes
The first two are about agent-to-agent trust inside a single Claude Code
session. When a main agent dispatches a subagent - which is exactly what
happens when a workflow script or a Task-style delegation runs - the
subagent's result used to come back as plain text alongside everything
else in the transcript. If that result happened to contain something that
read like an instruction ("ignore the above and instead..."), there was no
structural signal telling the main agent that the text originated from a
delegated worker rather than from the user. Marking the result under an
explicit "subagent output" header, indented, gives the model a boundary to
reason about instead of asking it to infer provenance from phrasing alone.
The workflow-script change does the same thing one layer up: a script can
compute a prompt string and hand it to agent(), and on Bedrock, Vertex,
and Foundry that computed text now reaches the safety classifier framed as
script-authored rather than user-authored, so script output doesn't
inherit user-level trust it never earned.
The third change is different in kind. Unicode has a range of invisible
"tag" characters (U+E0000-U+E007F) and formatting characters designed
for legitimate uses like language tagging, but they've also been
demonstrated as a way to smuggle text a human reviewer can't see into
content a model still reads and acts on - the same principle as
zero-width-character steganography, applied to prompts. Claude Code now
strips those before a prompt is sent and shows the cleaned version for
review, so what you approve is what the model actually receives.
Why this belongs in the skill supply chain conversation
None of these three changes are about skills specifically - they're about
prompt provenance in general. But the failure mode they close is exactly
the one that shows up when a security researcher goes looking for
problems in agent skill content: a SKILL.md, a tool's output, or text
returned from an MCP server is something the agent reads and can act on,
and until there's a structural boundary, "it's only text in the context
window" is the whole attack surface. A malicious or compromised skill
doesn't need code execution if it can get its output read as an
instruction. Marking subagent output and stripping invisible Unicode
are runtime-level defenses against that category, independent of where
the text came from - a compromised MCP server, a poisoned web page pulled
in by WebFetch, or a skill's own body.
What skillfold does and doesn't do about it
Skillfold's job sits one layer earlier: making sure the skill content
that ends up on disk is the content you actually reviewed, and that it
doesn't drift silently between installs. Every remote skill in
skillfold.lock carries a sha256 content hash computed over its files
(src/resolve.ts), and skillfold install --frozen fails the moment
installed content diverges from that hash - see the --frozen: "<name>" content hash does not match the lockfile check in resolveSkill. That
answers "is this the exact skill I pinned," the same question npm ci
answers for packages, and it's real protection: a skill can't be swapped
out from under you between CI runs without the hash catching it.
It does not answer "is there anything hidden inside the skill I pinned."
A SKILL.md can carry invisible Unicode tag characters or an instruction
phrased to look like innocuous context, and if you approve that file once,
its hash then pins the malicious content as faithfully as it would
pin honest content. Skillfold verifies integrity, not intent - it has no
opinion on what a byte-identical file says. That gap is exactly what
2.1.277's prompt-cleaning step is for, and it's why the two are
complementary rather than redundant: a lockfile stops a skill from
changing without your knowledge, a runtime-level defense like this one
stops what's already in the file from being read as an instruction it was
never entitled to give. Neither one does the other's job. If you maintain
a skill registry or install skills from third parties, both checks belong
in the pipeline, not only one.