I went to tidy up my Claude Code skills into a shareable marketplace. What started as housekeeping turned into a small security problem with my name on it. Over a year or so I’d accumulated a pile of workflows: the way I like a release set up, how docs get structured, a dozen little conventions all written down as CLAUDE.md files and skills scattered across projects. And I kept hitting the same friction. I’d start something new, want a workflow I’d already worked out somewhere else, and find myself telling Claude Code to go and read another project’s CLAUDE.md to pick it up. Do that often enough and the obvious thought arrives: these should live somewhere shareable. So I opened a marketplace, claude-code-plugins, to make them reusable, for me and for anyone who fancied aping my setup.
Then I remembered what I’d written the week before.
I’d just published the interpreter we forgot to sandbox, whose whole argument is that a SKILL.md or a CLAUDE.md is not documentation. It’s source code, in the sense that an agent reads it and acts on it, which makes it an injectable attack surface that nobody treats like one. And I’d then gone and built the ideal delivery mechanism for exactly that attack: a marketplace that accepts those files, by merge request, from people I don’t know, and hands them to other people’s agents to execute.
I’d built the gun and was halfway to loading it. The marketplace I’d opened to share my workflows was, viewed from one angle, a supply chain for the thing I’d just warned everyone about. So I had to defend it, and the awkward part was that the attack surface I most needed to defend against was my own. If anyone was going to be trusted blindly, it was me, which meant my markdown had to be the cleanest in the building.
The gate is a reusable CI component, skill-security, and it runs on every merge request to the marketplace. The headline check is the one straight out of that post: a hard fail on hidden characters. Zero-width spaces, and the bidirectional control characters behind Trojan-Source, the ones that let a diff read as one thing to a human reviewer and mean another to the machine. A U+200B you can’t see or a U+202E flipping text direction is precisely how you smuggle an instruction past review, so anything carrying them doesn’t get a warning, it gets stopped. On top of that there’s schema validation for the plugin and SKILL.md files, including which frontmatter keys are even allowed, injection heuristics that warn on the more suspicious patterns, and a scoped run of gitleaks so nobody fat-fingers a token into a skill.
I built it as a shared component rather than a one-off pipeline on purpose, the same move as CI you include, not copy and the build gate those sites never had. The scan isn’t special to the marketplace. Any repo full of skills or CLAUDE.md files has the same exposure, so the gate is a thing you include in one line and get for free, and the marketplace is just its first customer. Solve it once, wire it in everywhere.
And then, because a security control you haven’t watched work is a guess, I tried to beat it. Planted a zero-width space in one file and a direction-flipping character in another, the exact tricks the post describes, and ran the gate over the marketplace’s own contents before anything shipped. It caught both. That mattered more to me than it sounds, because the whole credibility of the thing rests on the author’s own files being clean. It would be a particularly bleak joke to publish “markdown is an attack vector” and then ship a marketplace of markdown that failed its own check.
What I’d take from it is about where you stand when you hand people a tool. Writing the warning is easy. Building the warehouse that all that warned-about stuff flows through is a different thing entirely. If you’re going to tell everyone their markdown is dangerous, the first markdown you make safe had better be the one with your name on it.
