Skip to content

fix: Look up DeepHashAccessor keys instead of defining methods - #580

Open
razor-x wants to merge 1 commit into
mainfrom
claude/ruby-sdk-audit-xbhaia-deep-hash-accessor
Open

fix: Look up DeepHashAccessor keys instead of defining methods#580
razor-x wants to merge 1 commit into
mainfrom
claude/ruby-sdk-audit-xbhaia-deep-hash-accessor

Conversation

@razor-x

@razor-x razor-x commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

SDK audit finding M10 (second part). DeepHashAccessor#create_accessor_methods called define_singleton_method for every key of the wrapped hash. custom_metadata and every undeclared nested object are wrapped this way, so caller-controlled keys shadowed the object's own methods: a "to_h" key replaced to_h (which ActionAttemptResolver.wait_options calls on the client defaults), a "class" key replaced class, and so on. Subscript access was respond_to?-based, so accessor["to_h"] returned the data whether or not that key existed.

Fix

Processed values live in a string-keyed hash; reads go through method_missing / respond_to_missing?, so a key can never replace a method, and [] reads only the data. Memoization of nested accessors is preserved. Also drops the unused require "date".

Tests

spec/deep_hash_accessor_spec.rb: respond_to? reflects keys only, a key called with arguments still raises NoMethodError, to_h and class keep their meaning while accessor["to_h"] and accessor["class"] return the data, and accessor["inspect"] is nil.

Revert-check against main: 4 failures, with to_h and class returning "shadow" and accessor["inspect"] returning the inspect string.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SQW83gyXeUG61RDrHEky97


Generated by Claude Code

DeepHashAccessor defined a singleton method for every key of the hash it
wrapped, so caller-controlled data such as custom_metadata could shadow
the object's own methods: a "to_h" key replaced to_h, which the action
attempt resolver calls on the client defaults, and a "class" key replaced
class. Subscript access also leaked every public method, so
accessor["to_h"] returned the data whether or not that key existed.

Keep the processed values in a hash and serve reads through
method_missing and respond_to_missing?, so a key can never replace a
method and subscript access reads only the data. Also drop the unused
require of date.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQW83gyXeUG61RDrHEky97
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants