Repository navigation
Description
[agent]
Summary
Some gem security fixes change only a C extension's sources: ext/**/*.c, *.h, extconf.rb and similar. Whether such a patch actually takes effect depends on the install mode:
| Mode | How the patch lands | Patched C code runs? | Current behavior |
|---|---|---|---|
Hosted (scan --mode hosted) |
The Gemfile gets a source "<patch registry>" block; bundle install fetches the patched .gem from the compact index |
Yes. Bundler installs it like any registry gem, so RubyGems runs extconf.rb + make on the patched sources |
Correct |
Vendored (vendor, scan/get --mode vendored) |
Path-sourced gem under .socket/vendor/ |
No. Bundler does not build extensions for path sources | Correct: refuses with native_extensions_unsupported (crates/socket-patch-core/src/vendor/gem.rs) |
Agent (apply, scan --mode agent) |
Rewrites the already-installed gem's files in place | No. Ruby loads the .so/.bundle compiled at install time; the edited .c is never compiled |
Bug: reports the gem as patched while the vulnerable compiled code still runs |
Example: every patch for json 2.10.x–2.17.x under GHSA-x2f5-4prf-w687 changes only ext/json/ext/parser/parser.c and/or ext/json/ext/generator/generator.c. In hosted mode these patches work. Agent-mode apply reports them applied, but the installed json/ext/parser.so is unchanged.
Requested changes
1. Agent mode: never report a native-extension-only gem patch as applied (required)
When a gem patch changes any native-extension build input, apply must not report success while the compiled extension is unchanged. Choose one:
- Refuse (simplest; matches vendored mode): fail that purl with
native_extensions_unsupported. Write nothing, and point the user atscan --mode hosted. - Rebuild (optional, later): after writing the patched sources, rebuild each affected extension against the active Ruby (the steps
gem pristine --extensionsruns:extconf.rb+makein the extension dir, then install the built artifact where RubyGems placed the original, underextensions/<arch>/<ruby-abi>/<gem>-<version>/and the gem'slib/). If no compiler toolchain or Ruby headers are available, fall back to the refusal.
A patch that changes Ruby files AND extension sources needs the same treatment. Applying only the Ruby half leaves the gem half-patched.
2. VEX must agree
vex must not attest a purl as patched when agent-mode apply was refused, or when the installed compiled extension does not come from patched sources.
3. Rollback (only if the rebuild option is built)
Rollback must also restore the original compiled extension, not only the source files.
Detection
Treat a changed file as a native-extension build input when any of these holds:
- Its extension is
.c,.h,.cc,.cpp,.cxx,.hh,.hpp,.hxx,.m,.yor.rl. - It is named
extconf.rb, or it isdependunderext/. - It is a file the gemspec's
extensionsentries build. The vendored backend already parses this ingemspec_declares_extensions.
Out of scope / already correct
- Hosted mode needs no change for these patches. Two existing behaviors still apply: a precompiled platform gem (e.g.
x86_64-linux) already fails closed withredirect_gem_platform_unsupported, and a frozen install must be unfrozen to pick up the patched gem (redirect_gem_frozen_install). - A gem Ruby loads as a default gem without a
Gemfile.lockentry (json ships with Ruby) cannot be redirected in hosted mode. That is a separate limitation, not covered here.
Activity
[-]Rebuild gem native extensions when a patch changes their C sources[/-][+]Agent-mode apply reports gem native-extension patches as applied without rebuilding[/+]Wenxin-Jiang commentedon Nov 3, 2026
[agent] Related: SocketDev/depscan#29554 starts serving gem patches that change only native-extension sources, because hosted mode rebuilds the extension on install. Until this issue lands, agent-mode
applywill report those gems as patched while the old compiled extension still runs.