Ruby, Rails & AI Weekly Roundup: Resolv Gem DNS Flaws, lemans Goes Open Source, and RubyLLM 2.0 (Aug 23β30, 2026)
Ruby patches two resolv gem DNS vulnerabilities, the Rails Foundation open-sources its lemans AI-agent benchmark harness, and RubyLLM 2.0 splits providers from protocols.
The week of August 23β30 belonged to infrastructure most Rails apps touch without thinking about it: DNS resolution, ERB compilation, and schema introspection. Ruby core shipped a security advisory for the resolv gem, Rails core merged a new HTML-aware template engine and a breaking config change, and the Ruby AI-tooling world had its busiest week in months courtesy of the Rails Foundation and RubyLLM. None of it requires a scramble, but a few items belong on this week's list.
Ruby patches two DNS resolver flaws: CVE-2026-80212 and CVE-2026-80213
Ruby's security team disclosed two vulnerabilities in the resolv gem on August 27: CVE-2026-80212, a memory-exhaustion bug, and CVE-2026-80213, a hostname-validation bypass. Both hit code that resolves a hostname an attacker can influence β a webhook target, a user-supplied URL β through Resolv directly, through resolv-replace, or through a dependency that routes name resolution the same way.
CVE-2026-80212 lets an attacker point a domain at a name server they control and return DNS responses the library retains without bound; repeated lookups grow the process until it runs out of memory. CVE-2026-80213 is the sharper one if you do SSRF filtering: it lets a hostname that passes an allow-list check resolve to a different name than the one that was validated, provided the hostname exceeds DNS length limits (255 octets total, 63 per label). Validation that already rejects names past those limits is unaffected.
Ordinary socket code β Net::HTTP, TCPSocket β uses the OS resolver and isn't exposed, even though Net::HTTP loads resolv for its IP-address regexes. Affected versions run from 0.3.1 and earlier through 0.7.1; Ruby 4.0 ships resolv 0.7.0, Ruby 3.4 ships 0.7.1, Ruby 3.3 ships 0.3.1. Update to resolv 0.7.2 (0.3.2 on the 3.3 series). Ruby 3.2 is end of life and gets no dedicated patch β install 0.7.2 there directly. Credit for the find goes to security researcher dalifit.
lemans: the Rails Foundation open-sources the harness behind Agents on Rails
On August 24 the Rails Foundation open-sourced lemans, the Ruby-native benchmark harness behind the Agents on Rails leaderboard, alongside four new model runs. lemans replaces the Python-based Harbor the team started with, and it's worth a look if you've wanted convention-over-configuration tooling for grading coding agents against real Rails tasks instead of generic leaderboards.
The four new entrants told an uneven story. Qwen3.8-27B, the open-weight model small enough to self-host, scored 48 of 63 but took a median 27 minutes per run β the team had to raise its timeout from 30 to 60 minutes β with the worst Rails-API recall in the field at 7.9%. Terra scored 49 of 63 for 20 cents a run at a 182-second median, now the fastest model tested. Anthropic's Sonnet 5 landed at 44 of 63, the family's weakest result recorded and a wide spread from Opus 5's 92%.
Install with gem install lemans against the ai-evals repo, point it at a Daytona or local Docker sandbox, and run lemans run --model <provider>/<name> --task <task> --attempts 3. Any RubyLLM-supported provider works. The harness restores test/, bin/, and config/environments/test.rb from a pre-run snapshot before grading, so an agent can't rewrite the tests it's judged against, and it strips known provider credentials from every file it writes to disk β a defense added after a prior run leaked an OpenRouter key into a published trajectory file.
RubyLLM 2.0 splits providers from protocols
Carmine Paolino previewed RubyLLM 2.0 across two posts this week, starting August 27 with a rewrite that splits providers β the service you connect to β from protocols β the wire format it speaks. In 1.x, providers like Mistral inherited from OpenAI to reuse request code and then had to undo the assumptions that didn't apply. In 2.0, a provider registers the protocols it supports and picks one per model; the entire Mistral provider is now about 25 lines.
The change most apps will notice: OpenAI now defaults to the Responses API instead of Chat Completions, since Responses is the only one of the two that lets reasoning models use tools and extended thinking together. Opt back into Chat Completions per-chat with protocol: :chat_completions, or globally via config.openai_protocol. AWS Bedrock gets the same treatment β Claude speaks Anthropic's Messages API, five models speak Responses, the other forty-one speak Chat Completions, all behind one host β and RubyLLM now routes automatically, including mid-conversation with .with_model.
Four new providers (Cohere, Ollama Cloud, ElevenLabs, Deepgram) bring the total to seventeen, and a ruby_llm provider-gem generator scaffolds a complete external provider gem β Git init, bundler, CI, RuboCop, live-recording specs β for anyone who doesn't want to wait for a provider to ship in core. RubyLLM 2.0 wasn't yet released as of this writing; treat this as advance notice rather than an upgrade to schedule.
Herb brings an HTML-aware ERB engine to Action View
Rails merged support for Herb as a new ERB implementation on August 25. Herb parses HTML and embedded Ruby into a single syntax tree β using Prism for the Ruby half β instead of treating ERB as opaque text the way Erubi does, which means a template that would produce invalid HTML or invalid Ruby fails at compile time instead of at render time in production.
ActionView::Template::Handlers::ERB::Herb is built as a drop-in, byte-for-byte-compatible replacement for Erubi; actual escaping still happens in ActionView::OutputBuffer at render time, unchanged. The herb gem is now a dependency of actionview alongside erubi, but there's no framework-default flag yet β you'd need to set ActionView::Template::Handlers::ERB.erb_implementation = ActionView::Template::Handlers::ERB::Herb yourself to try it. A follow-up PR proposing config.action_view.html_aware_erb is expected, with maintainers discussing a default of true in Rails 8.2; apps not ready to move could flip it back with config.load_defaults 8.2. Worth watching if your team maintains ERB linting, since Herb's structural understanding is also what powers its standalone linter, formatter, and language server.
Rails unifies schema-ignore configuration β and it's a breaking change
Rails merged a small, genuinely breaking config change on August 26: config.active_record.schema_ignored_tables replaces both ActiveRecord::SchemaDumper.ignore_tables and config.active_record.schema_cache_ignored_tables, which previously had to be set separately to exclude a table from both schema.rb and the schema cache. Both old settings are deprecated β their readers and writers now warn and delegate to the new one β but the merge exposed a real inconsistency worth checking before you upgrade.
The two old configs matched table names differently: SchemaDumper stripped table_name_prefix/table_name_suffix before comparing against your ignore patterns, while SchemaCache compared against the real database name. With table_name_prefix = 'omg_' and an ignore pattern of /^_/, a table named _rats (physical name omg__rats) used to get ignored by the dumper and not by the cache. After this change, both match against the physical name, so that same pattern needs updating to catch a prefixed table. Rails' own internal tables (schema_migrations, ar_internal_metadata) are unaffected; they're now wrapped with the prefix/suffix automatically before being added to the ignore list. If you use table_name_prefix or table_name_suffix together with either deprecated config, re-check your ignore patterns against the physical table names before you land on a Rails version that includes this commit.
Editorial pick: "RubyLLM 2.0: The Agentic Loop, Exposed"
Carmine Paolino's follow-up post earns the 20 minutes on its own. RubyLLM 1.x ran the model-call-then-tools loop inside a sealed ask method; 2.0 exposes it as verbs β ask_later, generate, run_tools, step, complete? β that you can drive from a background job, one turn per job, so an agent survives a worker restart and resumes from persisted messages instead of losing its place. chat.cancel! sets a flag another thread, or on Rails another request, can trip through the database, no Redis pub/sub required. The halt() escape hatch from 1.x tools is gone; stopping the loop is now the caller's job, not the tool's. If you're weighing whether to build agent workflows on ActiveJob, this is the clearest write-up of the tradeoffs you'll find this month.
Action items for the week
- Upgrade the resolv gem to 0.7.2 (0.3.2 on Ruby 3.3) if anything in your stack calls
Resolv, loadsresolv-replace, or resolves a hostname an attacker can influence β this is a CVE, not a nicety. - Before you land on a Rails version past August 26, audit any
table_name_prefix/table_name_suffixcombined withschema_cache_ignored_tablesorSchemaDumper.ignore_tablesβ the match target changed from logical to physical table names. - Point
lemansat your own Rails PRs to see how the model you're already paying for performs on Rails-shaped tasks instead of trusting a generic leaderboard. - Hold off pinning RubyLLM 2.0 until it ships, and if you use
halt()inside a tool today, plan the rewrite β it's removed in 2.0. - If your team maintains ERB linting or tooling, watch for the
config.action_view.html_aware_erbfollow-up PR; Herb is opt-in now but trending toward a Rails 8.2 default.
Comments
Sign in with Google or GitHub to comment.