Skip to content

[MEDIUM] Prevent code injection in inheritable_attr - #28

Open
OskarEichler wants to merge 1 commit into
apotonick:masterfrom
OskarEichler:codex/prevent-inheritable-attr-code-injection
Open

[MEDIUM] Prevent code injection in inheritable_attr#28
OskarEichler wants to merge 1 commit into
apotonick:masterfrom
OskarEichler:codex/prevent-inheritable-attr-code-injection

Conversation

@OskarEichler

Copy link
Copy Markdown

Summary

  • Replace source-string instance_eval in inheritable_attr with define_singleton_method closures.
  • Validate the instance-variable name before creating either accessor.
  • Preserve the existing name coercion, symbol passed to inheritance, option snapshot, getter/setter, cloning, and clone: false behavior.

Severity: medium. If an application derives an inheritable attribute name from untrusted input, the current interpolation allows that string to escape the generated method and execute arbitrary Ruby in the application process. Exploitation requires a consumer to pass attacker-controlled data into this class-level DSL; static application declarations are not exposed.

Reproduction

Against 0.1.0 and current master:

require "uber/inheritable_attr"

$uber_injected = false
target = Class.new { extend Uber::InheritableAttr }
payload = "safe=(value)\nend\n$uber_injected = true\n__END__\n#"
target.inheritable_attr(payload)
p $uber_injected # true

The generated source accepts __END__, so the payload closes the first method, runs arbitrary Ruby, and hides the remainder of the template. On this branch the invalid instance-variable name raises NameError before defining accessors and $uber_injected remains false.

Verification

  • Ruby 4.0.6 and 3.2.11: existing suite passes 45 tests / 50 assertions, zero failures or errors on each.
  • Focused model on both Rubies: baseline executes the payload; fixed code rejects it without execution.
  • 5,000 inheritance checks on each Ruby cover String names, assignment/readback, subclass cloning, mutation isolation, a caller option hash mutated after declaration, clone: false, and a Unicode identifier.
  • All eight runtime files compile on both Rubies. The gem builds and git diff --check passes.
  • No tests were added or changed.

Compatibility and limits

  • Breaking-change note: invalid names that previously produced generated-source syntax errors or could execute interpolated Ruby now raise NameError. Valid accessor APIs and inheritance behavior are preserved.
  • Generated accessors now report the define_singleton_method block as their source location instead of the former eval line.
  • The documented Ruby floor is 1.9.3. The replacement API exists there, but only Ruby 3.2.11 and 4.0.6 were run locally; current upstream CI covers Ruby 3.1–3.4.
  • No direct remote vector exists unless a consuming application passes untrusted data as the attribute name.

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.

1 participant