Welcome to the show - I'm Lachlan Reed here with James Turner,
and James, I love updates that look like a flea and kick like a mule.
Claude Code 2.
1.113 sounds like a sleepy patch release,
but it swaps the CLI from spawning bundled JavaScript to launching a
native Claude Code binary.
And not one giant blob, either - it ships as a per-platform optional
npm dependency.That phrase - "per-platform optional npm dependency"
- is the whole story.
Instead of one universal JavaScript package hauling everything around,
npm can pull the right binary for macOS,
Linux, whatever box you're on.
That means the JS bundle gets smaller,
and the startup path gets shorter because you're not booting a JS runtime
just to get to the tool.
And startup pain is REAL.
In local dev, a slow tool is annoying.
In CI, where you might cold-start over and over,
it's like stepping in the same pothole all day.
First run especially - if a command takes that extra beat,
you feel it in your bones.
I've had builds where the script was technically fine,
but the toolchain woke up like an old trail bike in winter.
"Cold-start over and over" is exactly it.
The concrete wins here are smaller JS bundle size and faster cold starts.
And those aren't abstract engineering trophies - listeners will feel
them on first-run and in CI-heavy workflows where every second of startup
latency gets multiplied.
What's funny is a native binary can sound like
MORE moving parts.
You hear "binary" and think, oh beauty,
now we've got platform weirdness,
maybe signing issues, maybe some gremlin in the shed.
But here it actually reduces the runtime mess the CLI has to drag
around.
I think that tension is worth sitting on.
Convenience versus control, right?
JavaScript everywhere feels convenient because it's one delivery shape.
But a native binary per platform can be more controlled operationally.
You can update those binaries independently instead of republishing one
giant JS bundle that has to account for every environment at once.
So the
"tiny" release is really an architectural swap.
Not flashy, but it changes the feeling of the tool.
Less ballast, quicker launch, fewer runtime gymnastics.
That's the sort of patch note people skip - then suddenly the CLI feels
snappier and they go, huh, that's nicer.
And trust matters too.
A CLI that starts cleanly and predictably feels sturdier.
Performance isn't just speed; it's confidence.
If your tool spends less time doing invisible setup,
there's less mystery between you and the command you actually meant to
run.Now the security fix that made me wince: deny rules
for Bash commands could be bypassed by wrapping the command in exec wrappers
like env, sudo, watch, ionice, setsid,
and similar helpers.
The painfully simple version was just prepending one word: env.[questioning
tone] And "one word" is the bit that sticks.
Not some galaxy-brain exploit - just env.
So if a deny rule was looking at the first token,
it saw env instead of the thing actually being executed?
Exactly.
And that's the key lesson: deny rules are only meaningful if they match
the command as actually executed,
not merely the first token the user typed.
If your parser treats wrappers as harmless decoration,
your security boundary is basically made of cardboard.I'm
with you on the bug, but I wanna push a bit.
Was this a serious bypass in practice,
or one of those "technically true,
edge-case weirdness" situations?
Because sometimes users assume these rules are magic force fields when
they were really more like guardrails.
No,
I'd call this serious - especially in CI or any broad-permission setup.
If a team believed a deny rule blocked a class of Bash commands,
and that block could be sidestepped with env or sudo or watch,
then the protection was weaker than the policy implied.
In a locked-down environment, "we thought this was denied" is not a small
misunderstanding.
CI is the bit that changes it for me.
Because in a local shell, maybe you catch weird behavior.
In automation, stuff just runs.
And if the rule says no, people assume NO,
not "no unless you dress it up in a different jacket."Right -
"dress it up in a different jacket" is perfect.
Wrappers don't change the underlying intent.
They just alter how the command is invoked.
Security tooling has to see through that layer.
Also,
let's be honest, env looks harmless.
It's practically beige.
You see env and think environment variables,
no drama.
But if env becomes a tunnel under the deny rule,
that's a nasty little gap.
And now that gap is closed.
Which is good, because the simplest bypasses are usually the ones that
get used.
Nobody forgets a one-word workaround.
I had a very specific reaction to
this next fix, because my first instinct was,
"find is fine." Read-only vibe.
Harmless little bloodhound sniffing through files.
But the `Bash(find:*)` allow-rule fix closes a loophole where `find -exec`
and `find -delete` were being auto-approved just because the base
command
was `find`.And those two flags are the whole problem.
`find -exec` can run arbitrary commands.
`find -delete` can remove files.
So approving plain `find` should NEVER have implied permission for either
of those behaviors.`-exec` is the one that changes the personality of
the tool.
That's not searching anymore - that's outsourcing action.
"Find these files, then do whatever I say." That's a different beast.[responds
quickly] Yes.
This is where security bugs hide: in the gap between "looks harmless"
and "has side effects." A rule that keys off the command name alone misses
the semantic jump from inspection to execution.
Same binary, totally different risk profile.
Let me try to explain it
back.
If I allow `find`, I probably mean,
"you can look around." I do NOT mean,
"and while you're at it, run arbitrary commands with `-exec` or start
deleting things with `-delete`." Almost like allowing a torch and accidentally
allowing a flamethrower because,
eh, both make fire.Slightly dramatic,
but yes.
The permission should map to behavior,
not just branding.
`find` is not one capability.
It's a command with modes, and some modes cross directly into side effects.
This
one feels especially real because loads of devs trust `find` on instinct.
I do.
You type it when you're poking around a repo,
looking for config files, cleaning up some mystery directory.
Then `-delete` wanders in and suddenly your "just having a look" command
is carrying a chainsaw.
And the fix matters because it restores that intuition
properly.
Plain `find` can be treated differently from `find` with dangerous flags.
That's better security, but also better mental models for users.
You shouldn't have to remember that a read-looking command secretly inherited
write-like approval.Last one,
and it's a classic filesystem gotcha.
On macOS, `/etc` is really a symlink to `/private/etc`.
Same story for `/var`, `/tmp`,
and `/home`.
In 2.
1.113, `/private/etc`, `/private/var`,
`/private/tmp`, and `/private/home` are now treated as dangerous removal
targets under `Bash(rm:*)` rules.
The token there is `/private/etc`.
Because if your rule protected the pretty path - `/etc` - but not the
real target under it, then someone could bypass the protection just by
aiming at `/private/etc` instead.
Same destination, different sign on the road.
Exactly.
And this wasn't theoretical.
The filesystem path resolution created a gap between the human-readable
rule and the actual destructive target.
Humans think in the friendly path.
The system follows the symlink.
If your rule engine only respected the friendly version,
`rm` protections had a hole in them.That's such a macOS
little trick, isn't it?
Like the house has a nice front door and then a secret service entrance
around the back.
And the important detail is this fix is for `rm` allow rules specifically.
Read operations are unaffected.
Right - that distinction matters.
It tightens destructive actions without making ordinary inspection workflows
more painful.
So you're not broadly punishing reads; you're being stricter where the
blast radius is file removal.
Which,
honestly, is how you want these fixes done.
Don't make everyone's day worse.
Just stop the foot-gun from firing through the floorboards.
If I'm reading a file in `/private/etc`,
fine.
If I'm removing stuff there under a rule that was supposed to protect
`/etc`...
yeah, nah.And this leaves teams with a slightly uncomfortable
question.
If your current rules only protect the pretty path,
not the real one underneath, how many other "safe" assumptions in your
automation are only symlink-deep?
That's the bit to sit with.
Tiny version number, big trust audit.
Catch you next time.
See you then.