Rubyland

news, opinion, tutorials, about ruby, aggregated
Sources About
Noteflakes 

A Look at Datastar

I have always been interested in frontend solutions for building web applications. Even though I’m more of a backend programmer, I really dig all the different techniques people come up with for creating browser-based apps that are both reactive (reflecting remote state in real-time) and interactive (responding to user actions).

Over the last few years, I’ve been looking at different frontend frameworks and libraries, to see how they work, and what I can learn from them. I adore Svelte, which is really smart and efficient. Its sister framework SvelteKit inspired the file-based routing in my own web framework for Ruby, Syntropy. I also really like the approach of the Phoenix framework…

Josh Software 

From One to Five: How We Solved a Real-Time Trading System’s Scaling Crisis

A story of race conditions, Docker containers, RabbitMQ queues, and the architecture decisions that kept our risk management platform alive under pressure. The Problem Nobody Wants on a Trading Floor Picture this: it’s 9:15 AM. The market just opened. Orders are flooding in — portfolio checks, risk calculations, compliance validations. And your Risk Management system? … Continue reading From One to Five: How We Solved a Real-Time Trading System’s Scaling Crisis
Rails Designer Blog 

7 modern CSS units your LLM keeps ignoring

Ask any LLM to style a layout and it uses CSS units like: px, rem, em, % and vh. So do you, out of habit. But CSS has grown its number of units. Ones that fit specific jobs way better than your old defaults. Here are seven your code generator has probably never suggested.

They are all baseline ready (e.g. supported by core browsers for at least 30 months), so there is no fallback excuse left. Let’s get into it.

Logical properties: think in axes (x and y)

A few of these units only make sense when you drop the ideas of “width” and “height” and think in axes instead. CSS now measures along the inline axis (the direction your text flows, left to right in, for example, English) and the block…

RubyGems Blog 

4.0.24 Released

RubyGems 4.0.24 includes enhancements, bug fixes and documentation and Bundler 4.0.24 includes enhancements and bug fixes.

To update to the latest RubyGems you can run:

gem update --system [--pre]

To update to the latest Bundler you can run:

gem install bundler [--pre]
bundle update --bundler=4.0.24

RubyGems Release Notes

Enhancements:

  • Installs bundler 4.0.24 as a default gem.

Bug fixes:

  • Skip executable removal gracefully when the bin directory is missing. Pull request #9963 by Evan Li and Hiroshi SHIBATA
  • Fix file locks letting multiple processes in when lock files are removed. Pull request #9930 by Richard Janita and Hiroshi SHIBATA
  • Turn off echo before printing the…

Documentation:

  • [DOC] Fix link. Pull request #10014 by Burdette Lamar

Bundler Release Notes

Enhancements:

  • Read the Ruby version from mise’s inline table form. Pull request #9991 by…
Evil Martians 

Why Buildkite hired Evil Martians for an agentic-first design system

Author: Varya Nekhina, Account ManagerTopics: Case Study, AI, DX, Design for devtools, UI coding harness, Agentic development, Figma, React, Ruby on Rails, CSS, Accessibility

Buildkite runs CI/CD for some of the most demanding engineering teams in the world. Why a team of opinionated developers hired Evil Martians to build a framework-agnostic design system with AI skills that guide coding agents through every component.

Buildkite is a high-scale, hybrid CI/CD platform that lets engineering teams run fast automated build, test, and deployment pipelines.

Planet Argon Blog 

Auditing a podcast email sequence with Claude

Auditing a podcast email sequence with Claude

If you've set up an automated email sequence and haven't reviewed it in a while, here's how to audit it with help from AI agents.

Continue Reading

RoboRuby 

Ruby AI News - November 4th, 2026

.bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; } .bh__table_cell { padding: 5px; background-color: #FFFFFF; } .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; } .bh__table_header { padding: 5px; background-color:#F1F1F1; } .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }

Welcome to the 40th edition of Ruby AI News! This edition features an avalanche of security issues, Ruby’s MCP SDK reaching Tier 1 status, a closer look at building AI evals for Rails, and much more.

Read on the web

Personal…

RoboRuby 

Newsletter Sponsorship Packages

.bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; } .bh__table_cell { padding: 5px; background-color: #FFFFFF; } .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; } .bh__table_header { padding: 5px; background-color:#F1F1F1; } .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }

New Sponsorship Opportunities

Ruby AI News has reached its 40th edition, and to mark it I am opening sponsorship packages that cover everything in the RoboRuby network. It is built for organizations that want in depth…

RubySec 

GHSA-2gff-2mmg-m73p (actionpack): Possible IP spoofing in Action Dispatch RemoteIp

### Impact Since Rails 8.1.0, `ActionDispatch::RemoteIp` derives `request.remote_ip` from `Rack::Request#forwarded_for`, which under Rack 3 reads the RFC 7239 `Forwarded` header in preference to `X-Forwarded-For`. When a reverse proxy appends the client address to `X-Forwarded-For` but passes a client-supplied `Forwarded` header through unchanged, `request.remote_ip` returns an address chosen by the client, and the IP spoofing check does not raise, because it compares only `Client-Ip` with the forwarded addresses. An unauthenticated attacker could therefore spoof `request.remote_ip`, possibly bypassing IP-based access controls and rate limits keyed on the client address (including the…
RubySec 

GHSA-2p2f-4rq4-gjwc (actionview): Possible XSS vulnerability in Action View text helpers

### Impact With the HTML5 sanitizer (`Rails::HTML5::Sanitizer`, the default vendor on CRuby for applications using `load_defaults 7.1` or later), Nokogiri before 1.19.5 serializes `<` and `>` unescaped inside attribute values. The Action View text helpers `highlight` and `simple_format` sanitize their input and then process the resulting HTML as a string: `highlight` splits it on tag boundaries to insert matches, and `simple_format` splits it into paragraphs on blank lines. An unescaped `>` or a blank line inside an attribute value could cause markup in that value, which the sanitizer left inert, to be emitted as live elements in the helper's `html_safe` output, possibly leading to…
RubySec 

GHSA-2w9f-fxwj-w2qf (activesupport): Possible XSS vulnerability in Active Support MessagePack serializer

### Impact `ActiveSupport::MessagePack` serializes an `ActiveSupport::SafeBuffer` as its bytes alone and deserializes it as a new `SafeBuffer`, so a buffer that is no longer `html_safe?` (for example, one mutated in place with `gsub!`) is restored as `html_safe`. If such a buffer holds untrusted input and is stored through a MessagePack serializer, rendering it after it is loaded bypasses ERB auto-escaping, possibly leading to XSS. Applications on Rails 8.1 are affected if they use a MessagePack serializer, such as `config.action_dispatch.cookies_serializer = :message_pack` or `:message_pack_allow_marshal`, or `serializer: :message_pack` for `Rails.cache`, `ActiveSupport::MessageVerifier`…
RubySec 

GHSA-3f4q-8x5m-76v8 (activestorage): Possible local file disclosure in Active Storage video previews and analysis

### Impact Active Storage's `VideoPreviewer`, `VideoAnalyzer` and `AudioAnalyzer` run `ffmpeg` and `ffprobe` on a blob's contents without restricting the input format, so FFmpeg selects a demuxer by probing the file. A blob created through a direct upload keeps the content type the client declared, so a client can store an HLS playlist under a `video/*` or `audio/*` type. When that blob is previewed or analyzed, the `hls` demuxer opens the `file://` segments that the playlist names, and the preview image or the stored metadata could disclose a local media file that the application process can read and whose path the attacker knows. Applications that accept uploads from untrusted users and…
RubySec 

GHSA-3w93-6hmw-whh4 (activestorage): Unsigned Content-Type in Active Storage GCS direct uploads with cache_control

### Impact When a GCS service is configured with the `cache_control` option, `ActiveStorage::Service::GCSService#url_for_direct_upload` signs direct-upload URLs with V4, and the V4 signature covers only the `Cache-Control` and `Host` headers. A direct-upload client can therefore send a `Content-Type` of its choosing, and can omit the declared `Content-MD5`, without invalidating the URL. GCS stores the supplied content type as object metadata, which takes precedence over the `response-content-type` that Active Storage sets on download URLs, so an uploaded object could be served as inline HTML under the application's bucket path on `storage.googleapis.com`. Script in such an object runs on…
RubySec 

GHSA-4v2w-w6g6-f8f8 (activestorage): Possible DoS vulnerability in Active Storage proxy mode via storage errors during streaming

### Impact When Active Storage serves a file through its proxy controllers, `ActiveStorage::Streaming#send_blob_stream` handles an error from the storage service by calling `head` to send a 404 or 500 response. If the error occurs after the first chunk has been written, the response is already committed, and `head` replaces the response body while the server is still reading the original `ActionController::Live` buffer. That buffer is never closed, so the server thread handling the request blocks until the process restarts. Repeated failed downloads could exhaust the server's threads, possibly resulting in a DoS vulnerability. Applications are affected when they store files on a service…
RubySec 

GHSA-5957-c7qm-m469 (actionmailbox): Possible signature replay in Action Mailbox Mailgun ingress

### Impact The Action Mailbox Mailgun ingress authenticates a request with an HMAC of the `timestamp` and `token` parameters concatenated without a separator, and `ActionMailbox::Ingresses::Mailgun::InboundEmailsController::Authenticator#recent?` rejects only timestamps more than 2 minutes in the past. Because the signature does not fix the boundary between the two values, a captured signed request can be presented with a timestamp far in the future, which the ingress then accepts indefinitely. An attacker who obtains one signed Mailgun webhook request, but not the signing key, could submit arbitrary inbound email that Action Mailbox processes as genuine, possibly leading to forged…
RubySec 

GHSA-68p9-83h6-5wpj (actionview): Possible XSS vulnerability in Action View tag helpers

### Impact The fix for [CVE-2026-33168](https://github.com/rails/rails/security/advisories/GHSA-v55j-83pf-r9cq) skips blank HTML attribute names in Action View tag helpers, but it tests the name before converting it to a string. A Symbol name made only of whitespace, such as `:" "`, is not blank, because `Symbol#blank?` is `Symbol#empty?`, so it reaches the attribute escaping, which emits an attribute with no name and produces malformed HTML. The asset tag helpers, such as `image_tag`, `video_tag` and `audio_tag`, symbolize their options, so a whitespace String name passed to them takes the same path. A carefully crafted attribute value could then be misinterpreted by the browser as a…
RubySec 

GHSA-8474-xrp6-wh69 (activesupport): Possible DoS vulnerability in Active Support safe_constantize

### Impact When constant lookup raises `LoadError`, `ActiveSupport::Inflector#safe_constantize` (and `String#safe_constantize`) builds a regular expression from the requested constant name without escaping it, so a caller that passes untrusted input lets the attacker choose the source of a pattern that the application compiles. Crafted patterns can trigger defects in Ruby's regular expression compiler, possibly leading to a crash of the server process, and repeated requests could keep the application unavailable. Action Cable passes the `channel` value of each `subscribe` command to `safe_constantize` before any channel lookup, so in the default configuration an unauthenticated client of…
RubySec 

GHSA-f3w6-w445-fwh9 (activestorage): Possible arbitrary file write and read in Active Storage image analysis

### Impact A Rails application that processes attachments with ImageMagick may allow an unauthenticated attacker to write arbitrary files on the server and, when attachments are stored with the Disk service, to read arbitrary files readable by the application process. Those files typically include `secret_key_base` and credentials for external systems, which may in turn allow escalation to remote code execution or lateral movement to those systems. ### Details ImageMagick selects a coder from the content of the file it is given, and some coders act on files named inside the image rather than on the image itself. Active Storage constrained none of ImageMagick's coders, and the…
RubySec 

GHSA-gmj8-hvj3-49mw (actionpack): Missing SameSite attribute on session cookies from Action Pack session stores

### Impact Action Pack session stores other than `ActionDispatch::Session::CookieStore` (`CacheStore`, `MemCacheStore`, and third-party stores built on `AbstractStore`, `AbstractSecureStore` or the session mixins) write the session cookie without a `SameSite` attribute, regardless of `config.action_dispatch.cookies_same_site_protection`, which defaults to `:lax`. Only `CookieStore` applies the configured policy. In browsers that do not treat a cookie without the attribute as `SameSite=Lax`, a cross-site request could carry the session cookie, possibly leading to cross-site request forgery against actions that do not verify an authenticity token, such as those of API-only…
RubySec 

GHSA-hfr4-8rjc-97m2 (activestorage): Possible circumvention of file size limits in Active Storage direct uploads to Google Cloud Storage

### Impact `ActiveStorage::Service::GCSService#url_for_direct_upload` does not bind the declared content length into the signed direct-upload URL, and `#headers_for_direct_upload` returns no length constraint, so the URL authorizes an upload body of any size. A direct-upload client could store a file larger than the `byte_size` it declared, and the resulting blob keeps the declared size, possibly bypassing application file size validations and quotas. This is the weakness that CVE-2020-8162 fixed in the S3 service. Applications that store files in Google Cloud Storage and accept direct uploads are affected. ### Details The fixed releases sign an `x-goog-content-length-range` header that…
RubySec 

GHSA-p2pm-g2h6-7j5j (activestorage): Possible DoS vulnerability in Active Storage filename handling

### Impact `ActiveStorage::Filename#base` and `#extension_with_delimiter`, and therefore `#extension`, pass the stored filename unmodified to `File.basename` and `File.extname`, which raise `ArgumentError` when the name contains a NUL byte. Active Storage stores the client-supplied filename verbatim, so a user who is permitted to upload an attachment could persist such a filename on databases that accept NUL bytes in string columns, such as SQLite and MySQL/MariaDB. Each subsequent request that builds a variant or preview of the blob, opens it, or renders it as an Action Text attachment then raises, possibly resulting in a persistent DoS vulnerability for the pages that display the blob…
RubySec 

GHSA-r9jg-fmfx-2gv6 (actionpack): Possible cache poisoning in Action Pack content negotiation

### Impact Action Pack negotiates the format of a rendered response from the `Accept`, `X-Requested-With` and, for XHR requests without `Accept`, `Content-Type` request headers, but `ActionController::Rendering#_set_vary_header` adds `Vary: Accept` only when the request carries a usable `Accept` header and the response has no `Vary` header yet. A response to a request without `Accept`, or to an XHR request, therefore omits the headers that selected its representation, and a response whose `Vary` the application set before rendering (for example `Vary: Accept-Language`) never gains `Accept`. A shared cache that honours `Vary` could store such a response and serve it to later clients that…
RubySec 

GHSA-rq8q-p985-fjq7 (actionview): Possible XSS vulnerability in Action View strip_tags

### Impact `strip_tags` in Action View returns its sanitized output marked `html_safe`, but the underlying sanitizer encodes only `&`, `<` and `>`, leaving `"` and `'` unencoded. Because ERB does not escape a string marked `html_safe`, untrusted input passed through `strip_tags` and rendered inside a quoted HTML attribute value could close the attribute and add new attributes, possibly leading to XSS. Applications that render `strip_tags` output from untrusted input inside an HTML attribute, for example in a `title` attribute or a `` tag, are affected. Output rendered as element content is not affected. ### Details `strip_tags` now encodes `"` and `'` in its output, as well as `&`, `<`…
RubySec 

GHSA-rwvh-fw6r-pwvp (actionpack): Possible DoS vulnerability in Action Controller Live streaming

### Impact `ActionController::Live::Buffer#close` pushes its end-of-stream marker onto the response's bounded queue while it holds the buffer's monitor. When the client has stopped reading and the queue is full, the push blocks, and `Buffer#abort`, which runs when the client disconnects or a write times out, waits indefinitely for the same monitor. Each such response could permanently hold a web server thread and its `ActionController::Live` thread, possibly resulting in a DoS vulnerability through thread exhaustion. Applications that stream responses with `ActionController::Live`, including `send_stream`, are affected. Applications that serve large files through Active Storage proxy mode…
RubySec 

GHSA-v6rj-xm57-3p59 (actionview): Possible XSS vulnerability in Action View highlight helper

### Impact `ActionView::Helpers::TextHelper#highlight` substitutes each matched phrase into the `:highlighter` string without escaping it and returns the result marked HTML-safe. Because sanitizing leaves quote characters in text unescaped, a match substituted into a quoted attribute value of the highlighter, such as the `` form shown in the method's documentation, could end the attribute value and add attributes to the element, possibly leading to XSS. Applications are affected when they pass a `:highlighter` that places a placeholder inside an attribute value and highlight text or phrases that a user controls. The default `\1` highlighter and the block form are not affected. ###…
RubySec 

GHSA-v924-7rp8-4mxh (activestorage): Possible arbitrary file read and remote code execution in Active Storage video previews, analysis and image processing

### Impact `ActiveStorage::Blob#open` writes a blob to a tempfile whose name carries the extension of the uploaded filename, and hands that path to `ffprobe` (`VideoAnalyzer`, `AudioAnalyzer`), `ffmpeg` (`VideoPreviewer`) and ImageMagick (`ImageAnalyzer`, the `:mini_magick` variant processor). These tools select a decoder from the file extension when the content does not identify its own format, so an attacker who chooses the filename and declares the content type of an upload chooses which decoder processes it. An FFmpeg built with AviSynth support treats a file with the `.avs` extension as an AviSynth script and evaluates it, which could disclose files readable by the application process…
RubySec 

GHSA-wm3x-v3qw-4jh3 (actionpack): Possible Strong Parameters bypass in Parameters#each_key in Action Pack

### Impact `ActionController::Parameters#each_key` delegates to the internal `ActiveSupport::HashWithIndifferentAccess` that holds the request parameters, so when called with a block it returns that hash instead of the `Parameters` instance. The hash does not respond to `permitted?`, so Active Model mass assignment (`new`, `assign_attributes`, `update`) accepts it without raising `ActiveModel::ForbiddenAttributesError`. An application that passes the return value of `each_key` to mass assignment could allow a remote, unauthenticated attacker to set attributes that the application does not permit, such as an authorization flag. This is an incomplete fix…
RubySec 

GHSA-x6mj-8jx9-qhqv (actionpack): Possible sensitive session information leak in Active Storage proxy mode

### Impact When `ActionDispatch::Cookies` reads a signed or encrypted cookie that was written under a rotated secret (`config.action_dispatch.cookies_rotations`) or in the format that a `:hybrid` cookie serializer migrates from, it writes the cookie back to the response in the current format, and that write ignores `request.session_options[:skip]`. `ActiveStorage::DisableSession` relies on that option to keep the session cookie off the public, immutable responses of the Active Storage proxy controllers, but those controllers still load the session, so a request carrying an old-format session cookie could receive the rewritten session cookie in `Set-Cookie` on a cacheable response. A…
code.dblock.org | tech blog 

How to Distribute a Rust App with Cargo, Homebrew, MSI, and WinGet

I recently ported my 1996 Pascal/Delphi calculator to Rust. The result is excalc, a cross-platform command-line application and MCP server.

Rust makes it easy to compile an application on every platform. Distributing it via crates.io, MSI, Homebrew or WinGet needed more work. Paste this cookbook into your favorite AI prompt to get it done.

We trigger a distribution from GitHub Releases: a Git tag identifies the new version, CI publishes the crate from that tag, builds portable archives and an MSI from that tag, and attaches everything to the release. Homebrew downloads the tagged source archive. WinGet points at the released MSI.

Prepare the Rust Package

Start with complete package…

The Ruby on Rails Podcast 

Episode 559: From Consulting to Rails Products with Eduardo and Camila Souza

What happens when the tool you rely on disappears? For Eduardo and Camila Souza, the shutdown of Pivotal Tracker became the motivation to build Pivotal Tasker, a Rails-based alternative inspired by the project management workflow they missed. They discuss reconstructing the experience from memory and reference material, adding classic and modern interfaces, and integrating coding agents to help create and work through stories.

The conversation expands into their move from consulting toward building products. Eduardo and Camila describe Chamber Builder, an all-in-one platform for chambers of commerce, and a custom sales CRM that brings calling, recordings, transcripts, and…

Graceful.Dev 

So long, RubyTapas.com

Five years ago, I announced that RubyTapas had become Graceful.Dev. But a revenant of that feast was left behind: the rubytapas.com site stuck around to handle billing for legacy customers, and I never got around to fully rolling that aspect into Graceful.Dev.

Until now. As of today, RubyTapas.com is no more. If you have a RubyTapas legacy account, it is now managed at Graceful.Dev. Same plan, same price, same access. Nothing changes except the words on the receipts, and there’s nothing you need to do.

And of course, all RubyTapas episodes are here at graceful.dev (as they have been for years). As well as lots and lots of post-RubyTapas content, organized into courses. The old…

Ruby on Rails: Compress the complexity of modern web apps 

Rails Versions 8.0.5.2 and 8.1.4.1 have been released!

Hello, Rails community!

Rails Versions 8.0.5.2 and 8.1.4.1 have been released. These are security updates addressing 21 security issues falling into a few themes:

  • Possible arbitrary file read, file write and remote code execution in Active Storage image and video processing
  • Possible Strong Parameters bypass in Parameters#each_key
  • Possible IP spoofing in remote_ip through the Forwarded header (8.1 only)
  • Multiple possible XSS vulnerabilities in Action View helpers, and one in the Active Support MessagePack serializer (8.1 only)
  • Possible DoS vulnerabilities in Active Support safe_constantize, Action Controller Live streaming, and Active Storage proxy mode and filename handling
  • U…

We strongly recommend upgrading as soon as possible.

Older versions of Rails are unsupported, and users are…

OmbuLabs.ai 

ChatGPT Can Now Use Your Apps

Every business has a list of jobs nobody wants and nobody can automate. Someone logs into a supplier portal every Monday to download invoices, then types them into the accounting software one line at a time. Someone else fills in the same government form every quarter, copying numbers from a spreadsheet into boxes on a website. Neither system offers a way for other software to connect to it (an API), the vendor isn’t going to build an integration for a customer your size, and so the work stays manual.

At the end of October, OpenAI released GPT-6.1 Terra, a model built for what OpenAI calls computer use: it looks at a screen, reads what’s on it, and clicks and types its way through apps and…

The Rails Tech Debt Blog 

What We Check Before Migrating Off Heroku

We recently moved a client’s Ruby on Rails app off Heroku: a Rails API with Sidekiq workers and several services around it. Before we changed anything, we spent about a week on discovery. We had a kickoff call with the client’s team on a Monday, and then two of us paired for the rest of the week to map the infrastructure and draft a migration plan.

Nothing about that app followed one pattern. Its services were deployed in different ways, and some of the things that mattered most for the migration, like the tools outside Heroku that read from the database and the service that promoted code to production, didn’t show up in the Heroku dashboard at all.

In this article, you will learn what we…

naildrivin5.com - David Bryant Copeland's Website 

Why Review AI-Generated Code?

AI can generate a lot of code quickly. There’s a thought that we can catch its mistakes or other issues by reviewing that code. In theory, this may be true; code review can catch bugs. In practice, it only works if the reviewer knows what to look for, has some context and, well, gives a shit.

There's a thought that we can catch mistakes in AI-generated code by reviewing it (or having an AI do that). This is short-sighted thinking, especially as developers lose the skill of code review entirely. Better to use AI to create better tooling.

This is all in a professional context, i.e. at a job. I don't think the conclusions here are necessarily relevant to hobby or open source…

Why Review…

Evil Martians 

The Agents on Rails Files: enter lemans, a Ruby harness for fair agent races

Authors: Vladimir Dementyev, Principal Backend Engineer, Artur Petrov, Backend Engineer, and Travis Turner, Tech EditorTopics: Rails, AI, Open Source, LLM benchmarking, Ruby, LLMs

A tour of lemans, the open source Ruby harness behind Agents on Rails: eval task anatomy, how it runs and grades coding agents for hours, and how cheaters shaped its guardrails.

Benchmarking coding agents in one sentence: give a model a task, let it work, check the result. The hard part is keeping the race fair. Every model must get the same conditions, and no agent should be able to escape its sandbox or fool its grader (and they try). And all of that has to keep running for hours. In the first post of The Agents…

Tim Riley 

Continuations 2026/44: More filtery

  • Milestone: this week I called a freeze on new Hanami work. From here we’re focused on cutting down our outstanding items and then switching to release prep.

  • I cut down a few items myself: three little pigs things to finish our Hanami CLI changes for compatibility with Dry CLI. This CLI is just right.

  • After some great feedback from Michael, I made a few adjustments to Dry Logger’s expanded log filtering (like making Regexp filters case insensitive by default, for consistency with string filters), and merged it. Thanks Michael! I also updated Hanami’s default list of filters. Combined with Dry Loggers substring filtering, this will make for a much more filtery out of the box experience.

  • A…

Robby on Rails 

Oh My Scrobbles: A Last.fm Scrobbler for Apple Music on Mac

I’ve been building a new project in my spare time while working through ideas for a few other apps.

Naturally, I found something to get distracted with.

Oh My Scrobbles is a Mac app for scrobbling Apple Music (and Radio!) to Last.fm and exploring your old listening history.

Like most projects I actually follow through on… this started with a huge itch I needed to scratch. I have over 300,000 scrobbles. I take this shit very seriously. 😉

Oh My Scrobbles showing albums I returned to after quiet stretches in my listening history

It can sync my whole Last.fm history to my Mac and expose a local MCP server, so I can ask ChatGPT and Claude questions about it.

I used that to find the exact tracks I’d scrobbled just before and after creating my GitHub account in 2008. Apparently,…

Aha! Engineering Blog 

Moment of Ruby: an argument for nothing

Last week I learned a technique in Ruby so small and useful, I couldn't believe I hadn't come across it before. Suppose a method doubles as a getter and setter. Pass a value to update a setting, or pass nothing to read it: module Cloakable def clo
Gusto Engineering - Medium 

What Slash Commands Actually Do

Illustration of a glowing forward-slash doorway with four machines behind it: a scroll on a conveyor, a toolbox, and a note-feeding machine each send streams up into a cloud past small coin meters, while a switchboard on the ground stays connected only to itself.

Somebody at Gusto asked, during one of our internal AI AMAs, whether /login was costing them tokens. The answer came back yes, relayed into our Claude Code channel a few minutes later: /login "is an LLM call, which will take more time and end up with unnecessary token use," so run claude auth login from the CLI instead, because that one's instant and free. It came with receipts, sort of. Secondhand from someone who'd watched /login run up $3.

That felt off, so I went and checked. It’s off. /login never touches the model, in any config. It's a local command: it runs entirely on your machine and never builds a prompt, so there is nothing to send.

So where did the $3 come from? A leading space.…

RubySec 

GHSA-345x-3rq2-jfrm (loofah): SVG `` and `` bypass local-reference restriction in Loofah

## Summary Loofah restricts `href` and `xlink:href` on certain SVG elements to same-document references. Two elements escaped the restriction: - ``: `SVG_ALLOW_LOCAL_HREF` listed it in lowercase as `textpath`, but the HTML5 parser names the element `textPath` inside ``, so the check never matched on the HTML5 path. - ``: absent from `SVG_ALLOW_LOCAL_HREF`, so its references were never restricted on either path. `rails-html-sanitizer` reuses this safelist in its `PermitScrubber`, so it is affected too. ## Impact An external `href` or `xlink:href` on `` or `` survives sanitization. Firefox fetches the URL when rendering the content, which leaks the viewer's IP address, user agent,…
RubySec 

GHSA-3w22-6jfg-527w (nokogiri): Use-After-Free in Nokogiri when replacing an attribute value

### Summary Nokogiri's CRuby native extension could leave a Ruby wrapper pointing to freed memory when replacing the value of an existing XML attribute via `Nokogiri::XML::Node#[]=` or `Nokogiri::XML::Node#lang=`. If Ruby code had already accessed the attribute's child nodes, replacing the value could free those native child nodes while their wrappers remained reachable. Using one of those child nodes afterwards could cause an invalid read and a possible segfault. This is the same class of issue as [GHSA-phwj-rprq-35pp](https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-phwj-rprq-35pp), which was fixed for `Attr#value=` in Nokogiri 1.19.4. Nokogiri 1.19.5 preserves all…
RubySec 

GHSA-4p39-36wj-23h4 (nokogiri): Possible Mutation XSS when serializing `noscript` content in `Nokogiri::HTML5` documents

### Summary Nokogiri's HTML5 serializer did not escape text inside `noscript` elements, or `<` and `>` inside attribute values. When a document parsed with the default options is serialized, a browser with scripting enabled can parse the output into markup that Nokogiri's parser never produced. This is a mutation XSS for applications that sanitize untrusted HTML with `Nokogiri::HTML5`, allow `noscript` elements, and send the serialized output to browsers. Nokogiri 1.19.5 escapes both, as the HTML standard's serialization algorithm requires. Text inside `noscript` is still emitted unescaped for documents parsed with `parse_noscript_content_as_text: true`. Only the C extension (CRuby and…
RubySec 

GHSA-cpgf-5mjf-73p7 (rails-html-sanitizer): Possible regular expression denial of service with certain configurations of rails-html-sanitizer

## Summary `Rails::HTML::PermitScrubber` restricts the `href` and `xlink:href` attributes of SVG reference elements to local references. That check matched the attribute value against `/^\s*[^#\s].*/m`. In Ruby `^` anchors to every line start and `\s` matches newlines, so an all-whitespace value made the engine rescan the value from each of its line starts, taking time quadratic in its length. - Versions affected: `>= 1.0.3, < 1.7.2` - Not affected: `< 1.0.3` - Fixed versions: `1.7.2` CRuby 3.1 and earlier, and JRuby, are affected. CRuby 3.2 added linear-time regexp matching, which makes the pattern linear. JRuby's regexp engine does not. ## Impact An attacker who supplies HTML to be…
RubySec 

GHSA-h6v6-rg66-fqj4 (loofah): Mutation XSS in Loofah HTML5 scrubbers through unescaped attribute values

## Summary Loofah's HTML5 scrubbers could emit output that a browser parses into different markup, allowing mutation XSS. Nokogiri < 1.19.5 did not escape `<` and `>` in attribute values. When the output contained certain MathML, a browser treated markup inside an allowed attribute as live HTML. The `:strip` scrubber is affected in every browser. The `:prune` and `:escape` scrubbers are affected in WebKit browsers such as Safari. Nokogiri 1.19.5 escapes `<` and `>` in attribute values, as the HTML standard requires. Loofah 2.25.3 requires Nokogiri >= 1.19.5. ## Impact Applications that sanitize untrusted HTML with Loofah's HTML5 API (`Loofah.html5_fragment`, `Loofah.html5_document` and…
RubySec 

GHSA-h7wh-q2qr-458c (rails-html-sanitizer): Possible XSS via shared scrubber state in concurrent rails-html-sanitizer calls

## Summary `Rails::HTML::SafeListSanitizer` (both the HTML4 and HTML5 variants) shares one `Rails::HTML::PermitScrubber` across every `sanitize` call on the same instance, assigning its `tags` and `attributes` on each call without synchronization. Two concurrent `sanitize` calls with different `tags:` or `attributes:` options can interleave, so one call is scrubbed with the other call's allowlist. - Versions affected: `< 1.7.2` - Not affected: none - Fixed versions: `1.7.2` ## Impact Action View memoizes a single `SafeListSanitizer` per helper module and uses it for every `sanitize` call in the process, so in a multi-threaded server (for example Puma) all requests share the same…
RubySec 

GHSA-jcff-cj73-4w4f (loofah): Loofah allowed_uri? treats data:text&sol;html as safe text/plain

## Summary `Loofah::HTML5::Scrub.allowed_uri?` returns `true` for a `data:` URI whose mediatype is written with the HTML5 named character reference `&sol;` in place of the solidus. Loofah reads that mediatype as malformed and falls back to the allowed `text/plain`, while a browser decodes the reference and reads the same URI as `text/html`. ## Details `allowed_uri?` decodes HTML entities with `CGI.unescapeHTML`, which handles numeric character references but not HTML5 named character references. `&sol;` therefore survives normalization, so the mediatype carries no `/`, fails the MIME grammar, and falls back to the allowed `text/plain` under the WHATWG rule for a malformed…
RubySec 

GHSA-m3x9-938q-5767 (loofah): CSS url() sanitization bypass via escaped parentheses in Loofah

## Summary `Loofah::HTML5::Scrub.scrub_css` rejected any property whose top-level Crass tokens included a `:url` or `:bad_url`, and left `url` out of the allowed CSS functions. Both checks ran only against the first parse of the `style` attribute. When `scrub_css` rebuilt each property it emitted identifiers with their CSS escapes decoded, so parentheses written as escapes — `url\28 …\29` — hid the `url` token from the checks, and the rebuilt value was re-parsed into a live `url()` that nothing checked again. An escaped property name, six-digit escapes, escaped comments and escaped quotes all reached the same place. ## Impact A sanitized `style` attribute could make a viewer's browser…
RubySec 

GHSA-mf2j-8f84-cc9q (loofah): Regular expression denial of service in Loofah's SVG local-reference check

## Summary Loofah's HTML5 sanitizer restricts the `href` and `xlink:href` attributes of SVG reference elements to local references. That check matched the attribute value against `/^\s*[^#\s].*/m`. In Ruby `^` anchors to every line start and `\s` matches newlines, so an all-whitespace value made the engine rescan the value from each of its line starts, taking time quadratic in its length. CRuby 3.1 and earlier, and JRuby, are affected. CRuby 3.2 added linear-time regexp matching, which makes the pattern linear. JRuby's regexp engine does not. ## Impact An attacker who supplies HTML to be sanitized can consume CPU out of proportion to the input size, by sending an SVG reference element…
RubySec 

GHSA-p9wj-w8xq-vjx6 (loofah): Loofah allowed_uri? treats javascript: alert(1) as safe

## Summary `Loofah::HTML5::Scrub.allowed_uri?` returns `true` for a `javascript:` or `vbscript:` URI whose scheme is split by a numeric character reference without a trailing semicolon, followed by a character that `allowed_uri?` strips, such as a space or tab. A browser ends the reference at that character and reads `javascript: alert(1)` as `javascript: alert(1)`. ## Details `allowed_uri?` strips control characters and whitespace before it decodes numeric character references. Removing the character that ends a semicolon-less reference lets the reference run on into the following text, so `: alert` decodes as `Ϊ` (U+03AA) instead of a colon, and no scheme is detected. The same applies…
RubySec 

GHSA-v995-44v6-5fqm (nokogiri): Possible SSRF on JRuby when resolving external DTDs or entities with `NONET` set

### Summary On JRuby, the `NONET` parse option did not block an external DTD or entity whose system identifier used a short-form IPv4 host, such as `http://127.1/` or `http://169.254.43518/`, or was an absolute path such as `/x.dtd` in a document parsed from a network URL. An application that parses untrusted XML with `DTDLOAD`, `DTDVALID` or `NOENT` could be made to send network requests, potentially enabling SSRF. Nokogiri 1.19.5 applies the `XML::Schema` check from [GHSA-8678-w3jw-xfc2](https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-8678-w3jw-xfc2): with `NONET` set, only local resources are loaded. Only JRuby is affected. Default parse options are not…
Saeloun Blog 

Rails 8.2 adds fallback reads for RAILS_MASTER_KEY

Rails main lets ActiveSupport::EncryptedFile try comma-separated keys when decrypting, including keys supplied through RAILS_MASTER_KEY. This is unreleased Rails 8.2 development functionality; Rails 8.1.4 still expects a single key. Successful fallback reads do not establish support for multi-key writes or a complete credentials-editing workflow.

Try fallback reads with a disposable file

This standalone example generates its own keys and uses a separate example variable. It does not load application credentials or read RAILS_MASTER_KEY.

require "active_support"
require "active_support/encrypted_file"
require "tmpdir"
require "fileutils"

variable = "SAELOUN_SYNTHETIC_KEYS"
raise "Use an…
Drifting Ruby Screencasts 

Idempotency

In this episode, we look at several different examples of background jobs and how we can refactor them to handle situations where they get called twice from either a user action or a retry. We'll look at scenarios where we can prevent duplicate actions.
danielabaron.me RSS Feed 

IP-Based Route Restrictions on Heroku with Rails

Learn how to restrict admin routes to VPN IP addresses on Heroku using Rails Advanced Route Constraints.
RubySec 

GHSA-4rw8-495r-pf6j (graphql): Execution::Next renders objects whose authorized? check failed

In some cases, GraphQL::Execution::Next rendered results for objects whose .authorized? hooks indicated that the object was unauthorized.
RubySec 

GHSA-q3cc-p5hm-55wj (graphql): Interpreter runtime renders results from objects whose `.authorized?` checks had failed

The legacy interpreter (Execution::Interpreter) renders the original, unauthorized object when authorized? raises GraphQL::UnauthorizedError and Schema.unauthorized_object returns a replacement. Returning false correctly renders the replacement.
RubySec 

GHSA-4fqr-96q8-xrfx (sqlite3): Possible SQL query truncation when a string is 4 GiB or larger

sqlite3-ruby cast Ruby string lengths (long) to int before passing them to SQLite. On 64-bit platforms, a string of 4 GiB (2^32 bytes) or larger had its length wrap, so SQLite saw only the first length mod 2^32 bytes. An attacker who controls the length of a SQL string could truncate the query, for example dropping a trailing WHERE clause. The affected paths are: * the SQL passed to Database#prepare, #execute, and related methods * String and Blob values passed to Statement#bind_param and related methods * String and Blob values returned from SQL functions and aggregates defined in Ruby (Database#create_function, #create_aggregate, and related methods) ## AFTER PATCH sqlite3 v2.10.2…
RubySec 

GHSA-76hq-g43j-f2rr (wasmtime): Data race in WASI when calling functions with `gvl: false`

### Impact `Extern#to_func(gvl: false)` releases Ruby's Global VM Lock (GVL) for the whole duration of a WebAssembly call. Two WASI host paths that run during such a call access Ruby objects without re-acquiring the GVL: - Writes to stdout/stderr captured with `WasiConfig#set_stdout_buffer` or `WasiConfig#set_stderr_buffer`, which append to the Ruby `String` buffer; - The block given to `WasiConfig#socket_addr_check`, which is called to allow or deny socket operations. A guest can trigger these paths, for example by writing to stdout. If another Ruby thread runs while the call is in progress, the unsynchronized access to the Ruby heap is undefined behavior. In practice it has been…
RubySec 

GHSA-c9f2-f4vx-xq68 (wasmtime): Externref results may be stale references

Ruby values returned from Wasmtime through externrefs from function results or hostcall arguments may be invalid references. This is due to not making the Ruby garbage collector aware that the Ruby value referenced by the externref is still in use. ## Impact Using an externref returned from a Wasm function or an externref provided as an argument to a hostcall could trigger a segmentation fault crashing the host process.
RubySec 

GHSA-4w5q-wg7v-w6gp (addressable): Regular Expression Denial of Service in Addressable templates with several exploded variables

Within the URI template implementation in Addressable, expressions with several exploded variables (e.g., {+a*,b*}, {+a*,b*,c*}, {/a*,b*}, {?a*,b*}) generate regular expressions vulnerable to excessive backtracking. A run of members can be divided among the exploded variables in O(n^k) ways for k variables. When Template#match or Template#extract is called with a maliciously crafted URI, this can result in uncontrolled resource consumption, leading to denial of service. With 2.9.0, {+a*,b*,c*} takes over 12 seconds to reject 1 KB of input on MRI Ruby 3.2. Users of the URI parsing capabilities in Addressable but not the URI template matching capabilities are unaffected. Users who only call…
RubySec 

GHSA-539f-xcgw-2gjg (addressable): Addressable display_uri can show misleading hosts containing bidi and invisible characters

Addressable::IDNA.to_unicode decodes Punycode labels (labels beginning with xn--) that contain characters which change how text is displayed without being visible themselves. These include bidirectional controls such as U+202E RIGHT-TO-LEFT OVERRIDE and U+2066–U+2069, zero-width characters, and other invisible format characters. Addressable::URI#display_uri uses to_unicode, so it can display a host whose characters appear reordered or which looks identical to a different host. For example, the host of http://xn--abcmoc-dm0c.com/ is displayed as abc, U+202E, moc.com, and the override makes everything after abc render right to left. Parsing, host, normalized_host and any connection made from…
RubySec 

GHSA-8gmh-2hhj-2hv9 (addressable): Addressable URI normalization resolves some dotted path segments to the wrong path

Addressable::URI.normalize_path resolves some paths containing .. segments to a different path than RFC 3986 does. When a path climbs above the root before any other .. is resolved, the segments that later .. segments should remove are instead kept: /../../public/x/../../secret normalizes to /public/x/secret instead of /secret. URI#normalize, URI#join, URI#== and URI#=== all use this normalization. An application that checks a normalized Addressable path against an allowlist, but sends the original URI to something that resolves it according to RFC 3986, can be made to allow a request for a path outside the allowlist.
RubySec 

GHSA-9crm-g4mf-wc5j (addressable): Addressable display_uri can show misleading hosts with invalid Punycode A-labels

Addressable::IDNA.to_unicode, in the pure-Ruby IDNA implementation, decodes Punycode labels (labels beginning with xn--) that are not valid A-labels. Those labels are returned in decoded form, when they should be returned unchanged. That includes: * labels that decode to only ASCII characters, e.g. xn--google- decodes to google; * labels that decode to text that doesn't convert back to the same label (RFC 3490 §4.2), e.g. text that isn't in normalized form. Addressable::URI#display_uri uses to_unicode, so for https://xn--google-.example.org/ it displays the host google.example.org, while #host, #normalized_host and any connection made from the URI use xn--google-.example.org. An…
RubySec 

GHSA-9f42-57jx-vpp3 (addressable): Regular Expression Denial of Service in Addressable templates with multiple variables

Within the URI template implementation in Addressable, templates that put several variables in one expression generate regular expressions vulnerable to excessive backtracking: 1. Expressions with any operator other than + and # (e.g., {/owner,repo,ref}, {.a,b}, {a,b,c}, {;a,b,c}). The values are joined by an optional separator, so a run of characters can be divided among the variables in O(n^k) ways for k variables. 2. Expressions with the + or # operators and many variables (e.g., {+v1,v2,v3,v4,v5,v6,v7,v8,v9,v10}). A failing match is exponential in the number of variables. 3. Several single-variable expressions next to each other (e.g., {+a}{+b}{+c} or {a}{b}{c}),…
RubySec 

GHSA-j82w-28jv-3pmj (addressable): Regular Expression Denial of Service in Addressable templates with certain exploded expressions

Within the URI template implementation in Addressable, templates using the * (explode) modifier with the /, ., ;, ? or & operators (e.g., {/segments*}, {.ext*}, {;params*}, {?query*}) generate regular expressions vulnerable to catastrophic backtracking. When Template#match or Template#extract is called with a maliciously crafted URI that starts with the operator's leading character, matching takes exponential time, leading to uncontrolled resource consumption and denial of service. An input under 60 bytes is enough to occupy a thread for minutes. GHSA-h27x-rffw-24p4 (CVE-2026-35611) reported this pattern as fully remediated in 2.9.0. The 2.9.0 fix only made the joiner between exploded…
RubySec 

GHSA-qq38-m9mg-xjj5 (addressable): Denial of service in Addressable URI path normalization

Addressable::URI.normalize_path takes time quadratic in the number of nested dot segments in a path (e.g., "/" + "a/" * n + "../" * n, which for n = 3 is /a/a/a/../../../), because it removes one dot segment per pass over the whole path. URI#normalize, URI#normalized_path, URI#==, URI#=== and URI#join all call it. Normalizing, comparing or joining a URI taken from user input can result in uncontrolled resource consumption, leading to denial of service. On 2.9.0, normalizing a 34 KB path takes about 3.5 seconds on MRI Ruby 4.0, and the cost grows with the square of the path length. This affects every Ruby implementation, including MRI Ruby 3.2 and later. URI.parse by itself is unaffected,…
Alchemists: Articles 

Avoid Proton

Cover
Avoid Proton

We are, disturbingly, in a Gilded Age 2.0.0 era and, like the corrupt industrial tycoons of years past, we have tech tycoons forcing LLMs and data centers upon us. Software should be used to enhance and enrich the lives of staff and customers instead of extracting all their worth.

Worse, we have to be much more diligent about what we pay for and be quick to cancel when they disregard their engineers and customers. As was — and still is the case — where you must Avoid Zoom, you need to cancel any/all services with Proton as well. To quote from 404 Media:

Proton, the company behind ProtonMail and other privacy-focused products, told staff on Monday it would be…

Rails Revelry 

When Two Background Jobs Target the Same Record

Two jobs finish successfully. One account update disappears.

Suppose an account has 100 credits. You enqueue two jobs to add 10 and 20. Both jobs finish without an exception, but the account ends with 120 credits.

Each job runs this code:

class AddCreditsJob < ApplicationJob
  def perform(account_id, amount)
    account = Account.find(account_id)
    account.update!(credits: account.credits + amount)
  end
end

Assume credits is an integer column, with no optimistic locking or custom database rule protecting the update. These are application credits; the example doesn't model a payment system.

Two workers can execute the job in this sequence:

Job A (+10)       Job B (+20)
read 100
                …
code.dblock.org | tech blog 

Introducing Svet: A Git Repository Linter

The idea for Svet came from a private repository at work, where checking filename case helps catch portability problems like Logo.svg and logo.svg colliding on a case-insensitive Windows filesystem. These checks are implemented in pure JavaScript. That seemed like a useful job for a reusable repository linter.

I went looking for an existing tool.

Tool Why it isn’t enough here ESLint Can check filenames with a processor; byte-level checks and Git snapshots need custom plumbing. Oxlint Arbitrary non-JS/TS files don’t reach its lint rules. Biome Checks supported languages, not arbitrary repository…
Andy Croll 

Homebridge and Pi-hole on a Raspberry Pi 4

I had a Raspberry Pi 4B I thought might be dead. It wasn’t. I’m having a bunch of building work done and of course, the thermostats do not work with Apple HomeKit.

So the Pi now runs Homebridge, which puts our underfloor heating thermostats (and also now Samsung TVs) in Apple Home. For good measure it also runs Pi-hole, which blocks ads and trackers for every device in the house.

Gear required

I thought the Pi was dead

First I checked the cheap parts. SD cards and power supplies fail far more often than the Pis themselves.

  1. Removed and replaced…
RubySec 

GHSA-744p-w4gc-m3gh (trilogy): SQL injection through `Trilogy#escape` with multibyte encodings

`Trilogy#escape` produces unsafe output for Strings in Shift_JIS, Windows-31J, Big5, GBK or GB18030. In those encodings, the continuation byte of a multi byte character can be in the ASCII range. `escape` was intended for strict ASCII supersets and did not handle this correctly, which allowed SQL injection. ## Details Applications are affected in two cases: 1. On any connection charset, including the default `utf8mb4`, when an attacker can influence the encoding of a String the application escapes. 2. On connections configured with `encoding: sjis`, `cp932`, `big5`, `gbk` or `gb18030`. These connection encodings never worked correctly, are no longer supported, and now raise…
RubySec 

GHSA-2j8w-xcrc-x985 (rack): Rack::Request#host_with_port and `#base_url` return an invalid `Host` verbatim, enabling URL and allowlist bypass

Rack::Request#host_with_port, and therefore #base_url and #url, return the raw authority string when it fails validation. An attacker-controlled Host, X-Forwarded-Host, or Forwarded: host= value containing characters that are not permitted in an authority is embedded verbatim in URLs generated by the application. This completes the fix for CVE-2026-34835 (GHSA-g2pf-xv49-m2h5), which made #host and #hostname return nil for an invalid authority but left this path unchanged. ## Impact Applications that build absolute URLs, redirects, or origin-dependent checks from req.url, req.base_url, or req.host_with_port, and that do not enforce a host allowlist, may emit URLs containing…
RubySec 

GHSA-5v64-555j-wjxm (rack): Multipart parser retains parsed data in its scan buffer, allowing denial of service via memory exhaustion.

Rack::Multipart::Parser reads the request body in chunks of rack.multipart.buffer_size (1 MiB by default) into an internal scan buffer. Parsed bytes are only discarded from that buffer when a chunk ends inside a part body. A request whose parts are sized so that every chunk ends inside, or immediately after, a part's headers is never compacted, so the buffer grows to the size of the request. This results in a denial of service condition through memory exhaustion for applications that parse multipart requests. ## Impact Any application that parses multipart requests with Rack is affected in its default configuration. An unauthenticated attacker can cause a single request to hold memory…
RubySec 

GHSA-p8x9-v4hv-2w4g (rack): Multipart boundary guard skips a leading empty or quoted `boundary` parameter, allowing parser differentials and WAF bypass

The guard added for CVE-2026-26961 (GHSA-vgpv-f759-9wx3), which rejects multipart requests with more than one boundary parameter, only inspects the part of the Content-Type header after the boundary it extracts. A Content-Type whose first boundary parameter is empty or begins with a quote, semicolon, or comma is skipped by the extraction pattern, so a second boundary parameter is accepted silently and Rack parses the body with a boundary that a conforming parser would not derive from the header. ## Impact As with CVE-2026-26961, an attacker can craft a multipart request that a web application firewall or other inspecting proxy in front of a Rack application interprets differently from…
RubySec 

GHSA-wvg4-6p58-3gh3 (rack): Rack::Static `header_rules` bypass via unnormalized dot segments in the request path

Rack::Static normalizes the request path with Utils.clean_path_info when deciding which file to serve, but matches header_rules against a path that is only URL-decoded. A request containing dot segments, raw or percent-encoded, is served the normalized target file while the header rules for that file's location are not applied. This allows an attacker to receive a protected static file without the security headers configured for it. ## Impact Applications that use Rack::Static header_rules to attach security-relevant headers to particular paths or file types are affected. An unauthenticated attacker who knows the path of a protected file can request it through a dot segment path…
Julik Tarkhanov 

Batching the billing ledger (but with less)

Batching the Billing Ledger: Small Trade-Offs with High Impact is a great article about “systems assembly”, and microbilling is part and parcel of nearly any web app today, certainly when your users call into LLM models. Gotta keep’em tokens counted!

Since the start of the agentic era, I’ve been curious about “how much software” we need for workloads like this. After all, my doctrine is less stuff and this looked like a use case too perfect to pass on. Thank you, Vicente, for the pitch-perfect nerdsnipe!

So, here’s bab - but I am getting ahead of myself. First, we need the parts.


I am currently available for contract work. Hire meto help make your Rails app better! …


T…

RubySec 

GHSA-r47x-6p6r-mvcp (dalli): Keys created by incr or decr can forge get_multi replies

With the meta protocol, Dalli sends keys containing whitespace, control characters or non-ASCII characters base64-encoded. When `incr` or `decr` is called with an initial value and the key doesn't exist yet, memcached (verified with 1.6.45) creates the item under the decoded, raw key bytes and later echoes those raw bytes in `mg` replies. Dalli's pipelined `get_multi` parser trusted that echoed key, so a key containing CRLF split the reply header and the rest of the key was parsed as further replies. With a crafted key in the same `get_multi` batch, the block form of `get_multi`, `get_multi_cas`, and multi-server `get_multi` returned an attacker-chosen value for another requested key, which…
Ruby on Rails: Compress the complexity of modern web apps 

No tricks, just treats

Hi, it’s Claudio Baccigalupo. Don’t be scared 🎃 this week’s changes to the Rails codebase are all treats. Let’s explore them.

New guide to multiple databases in Active Record
As part of the Rails Foundation effort, the refreshed guide is live, tackling the three-tier production configuration that new apps get by default.

Tuning performance for deployment guide open for review
A PR that updates the guide to performance tuning is open. Your feedback is helpful, especially if you have experience tuning Rails apps in production.

Don’t load Capybara and Selenium on boot in new applications
The generated Gemfile now declares capybara and selenium-webdriver with require: false. ActionDispatc…

code.dblock.org | tech blog 

The Matter of Taste

While working on Svet, a Git and filesystem linter, I had a conversation with GitHub Copilot CLI about a flag.

The tool checks files. We were adding automatic fixes. Naturally, I wanted to preview changes before allowing the tool to write them.

The first suggestion was --fix-dry-run. I preferred a global --dry-run that could apply to both checking and fixing.

Simple enough. Except checking already doesn’t write anything. What should a dry run of a check do?

One answer is that a dry run prohibits writes. Run all the checks, report the findings, and leave the files alone. With --fix, calculate the fixes but don’t apply them. Without --fix, the flag changes nothing.

That’s a consistent…

Rails Revelry 

Your Rails debugging field guide

I’ve put together “Which Rails Layer Owns This?”, a six-page reference for when production Rails does something you didn’t expect.

Use it to find the layer to inspect: request handling, identity, loaded records, database writes or background work. Each page gives you checks to run, evidence to collect and links to the full explanations.

Download the attached PDF and keep it beside your logs the next time you’re tracing a production bug.

RubyMine : Intelligent Ruby and Rails IDE | The JetBrains Blog 

Compromised eMudhra Certificates: Update Your JetBrains IDEs, ReSharper, .NET Tools, Toolbox App, and Gateway Now

Summary

  • The private keys of eight eMudhra intermediate certificates were compromised. A network attacker could use them to impersonate websites and services that JetBrains tools connect to.
  • JetBrains IDEs, the Toolbox App, Gateway, and ReSharper are affected because they use the trust store of the bundled JetBrains Runtime (JBR). For IDEs, the embedded browser (JCEF) is also affected. Operating system updates don’t protect against this issue. 
  • The Toolbox App and JetBrains IDEs use a background service, jetbrainsd. It has its own built-in list of trusted certificates and is fixed separately, in jetbrainsd 0.9.9728.
  • At the time of publishing, we are not aware of any…

Available fixed versions

The issue is fixed in the following versions:

  • IntelliJ IDEA: 2026.3 RC, 2026.2.4, 2026.1.5.1, 2025.3.6.2, 2025.2.6.4.
  • PyCharm: 2026.3 RC, 2026.2.4, 2026.1.5.1, 2025.3.6.2, 2025.2.6.3.
  • PhpStorm: 2026.3 RC, 2026.2.4, 2026.1.5.1, 2025.3.6.2, 2025.2.6.3.
  • RubyMine: 2026.3 RC, 2026.2.4, 2026.1.5.1, 2025.3.6.2, 2025.2.6.3.
  • WebStorm: 2026.3 RC, 2026.2.4, 2026.1.5.1, 2025.3.6.2, 2025.2.6.3.
  • Rider: 2026.3 EAP 9, 2026.2.4, 2026.1.5.3, 2025.3.5.3.
  • CLion: 2026.3 RC, 2026.2.4.1, 2026.1.5.2, 2025.3.6.3, 2025.2.6.3.
  • DataSpel…

The 2025.2.6.* updates for all IDEs now…

Remote Ruby 

RWX Agent-native CI/CD with Dan Manges

This week on Remote Ruby, Chris, Andrew, and David welcome Dan Manges, co-founder of RWX and former CTO of Braintree, to explore a new approach to continuous integration built for the age of AI coding agents. Dan explains how RWX uses intelligent caching, graph-based execution, and isolated agent sandboxes to dramatically improve development workflows. They dive into flaky tests, automated code validation, security concerns, and why traditional CI platforms may be struggling to keep up with AI-driven development. Plus, they discuss how engineering teams can test changes before opening pull requests, reduce infrastructure costs, and rethink the way software gets built and shipped. Hit…

Greg Molnar 

SQL injection in the Trilogy MySQL adapter

This post has an important update, please read it. Two things below turned out to be wrong: the force_encoding in the proof of concept is not necessary, and the Rails parameter encoding check is not the mitigation I thought it was. This is exploitable with a single request against an app that does nothing unusual, if there is an Active Record query with two slots using `escape`, the app can be exploited, so read the update at the end of the post.

RailsCarma – Ruby on Rails Development Company specializing in Offshore Development 

What Is AngularJS Mobile App Development? A Complete Guide for 2026

If you are planning a mobile product and your team already knows JavaScript, AngularJS mobile app development is a phrase you have probably come across. It sounds simple: use a web framework to build an app that runs on iPhone and Android. The reality in 2026 is more nuanced, and getting it wrong can cost you months of rework.

This guide explains what AngularJS mobile app development really means today, how the technology works, where it still makes sense, where it does not, and what a smart path forward looks like. Whether you are a CTO maintaining a legacy product or a founder comparing frameworks, you will leave with a clear, practical…

Josh Software 

Beyond the Perfect Demo

Imagine spending weeks preparing for an important demo. You’ve rehearsed every flow, verified every functionality, created the perfect test data, and tested the application one last time before walking into the meeting. You know exactly which buttons you’ll click, what features you’ll highlight, what words you’re going to say, and even where you’ll pause for … Continue reading Beyond the Perfect Demo
Ryan Bigg Blog 

Hands on the wheel

(I’m still looking for my next gig. You can get in touch by emailing job@ryanbigg.com.)

As someone with infinite spare time, I feel qualified to share my opinion on AI by carving a post out of the raw marble of my keyboard with my bare hands.

I wrote this on LinkedIn at the start of this month:

After interviewing now at a few places these things are simultaneously true:

  1. EVERYONE is on the hype train
  2. Nobody knows how to REALLY use AI and people are trying to figure that out
  3. There are a lot of experiments that sound promising on the cover, but nothing past “we’re gonna go THATAWAY”
  4. There is an unlimited budget for this exploration, until there won’t be

I’ve now…

Awesome Ruby Newsletter 

💎 Issue 545 - Carton - Real boundaries for Ruby

John Nunemaker 

Don't Make a Human Do What AI Is Amazing At

Last weekend we were camping. Fall break. Glorious northern Indiana weather. My kids were fishing with grandpa, so I went for a walk around the campground (to check out the other rigs as dads do). Somewhere along the way I opened T3 and told Nunebot to do another run. Merge, merge, merge, run it again, merge, merge. Just getting some exercise and enjoying the fall weather.

Between Saturday and Sunday I merged 113 pull requests. Definitely the most in a two day span in the two decades I’ve been doing this.

I know how that sounds. But I honestly like this more than games, mindless scrolling, or Instagram. It’s relaxing for me. Read a PR, it makes sense, merge. Little dopamine hit. Next.

I’ve…

avdi.codes 

https://avdi.codes/191403-2/?utm_source=rss&utm_medium=rss&utm_campaign=191403-2

you can train someone to be better. You can’t make someone care about things they don’t intrinsicly value.

naildrivin5.com – David Bryant Copeland’s Website: You Cannot Trust the AI Code Generator

code.dblock.org | tech blog 

One Tool for the (Spell Checking) Job

I’ve built five spell-checking plugins in the last week. This is not an unhealthy interest in spelling. The cost of rolling tools out is the cost of tokens + my time supervising AI. So, before adding another language runtime, package manager, configuration file, and CI job to your project, consider spending an hour vibe coding the missing plugin.

This blog used to run a Python spell checker that took more than three minutes. It’s a Jekyll blog, which is Ruby. Why was I maintaining a Python environment to tell me that I misspelled “hello”? I replaced it with a RuboCop plugin. Spelling became another cop, with the same configuration, exclusions, command, and CI integration as the rest of the…

A Rust project…

Ruby Weekly 

How fast can you actually patch Ruby?

#​824 — October 29, 2026

Read on the Web

🔒 Last Friday we sent out a special issue about some CRuby security releases which fixed a few nasty regexp bugs. If you haven't updated yet, it's worth a read to see if you're affected and what to check!
__
Your editor, Peter Cooper

Ruby Weekly

How Fast Can You Actually Patch Ruby? — When the Ruby security fixes shipped last week, Dennis timed how long they took to reach version managers, Docker images, CI services and hosts. The core team's image took eight minutes, while Docker's official image (Rails and Kamal's default) took ~16 hours.

Dennis Paagman

💡 Things are improving,…

All about coding 

Superpowers Ruby is becoming RubyPowers

Superpowers Ruby becomes RubyPowers in version 8.0.0. Existing users need to migrate their plugin installation and update saved skill references; existing plans and specs remain supported.
Rails Designer Blog 

Introducing Hanami Icons

Most of what can be read here is around and for Ruby on Rails. My main apps still are powered by it. But monopolies are never good. Hanami is the one I get most excited about.

It is why I extracted the core features (pulling SVGs from remote repository, transforming filenames, etc.) of Rails Icons into a Ruby gem, called Icons, so other frameworks can have all the icons in their apps as well.

Hanami Icons is the next wrapper of the Icons gem for… drumroll… Hanami! It gives you the same interface as Rails Icons too, whether that is Heroicons, Lucide, Tabler or even a folder of your own SVGs.

<%== icon "check", class: "text-gray-500" %>

<%== icon "apple", library: "simple_icons", class:…

if you have seen Rails icons, you…

RubyGems Blog 

Ruby Central’s OSS Changelog: October 2026

Originally published on Ruby Central.

Relaunching the changelog

It has been a long time since the last Ruby Central Changelog, and we’re bringing it back. Ruby Central’s open source team operates RubyGems.org, a service many of us rely on every day, and supports the packaging ecosystem around it. The Changelog is where we will share that work. Each issue will cover what is changing, why it matters, and where you can get involved.

This is the first issue edited by our new Community Manager, Kirk Haines, who joined Ruby Central in August. If you missed his introduction in the Ruby Central August README, the short version is that Kirk has been using Ruby since 2001 and is glad to give back…

Ruby Central 

Ruby Central’s OSS Changelog: October 2026

Relaunching the Changelog

It has been a long time since the last Ruby Central Changelog, and we’re bringing it back. Ruby Central’s open source team operates RubyGems.org, a service many of us rely on every day, and supports the packaging ecosystem around it. The Changelog is where we will share that work. Each issue will cover what is changing, why it matters, and where you can get involved.

This is the first issue edited by our new Community Manager, Kirk Haines, who joined Ruby Central in August. If you missed his introduction in the Ruby Central August README, the short version is that Kirk has been using Ruby since 2001 and is glad to give back to the language and the community that…

Super Good Blog 

Setting Up a New Solidus Store

Starting a new Solidus store involves only a few tweaks to support my preferred JS bundler, as well as a number of decisions regarding hosting, databases, assets and more. This is the sequence of steps I follow to launch a fresh store.

For the purposes of this demo, I have intentionally left out some of the details regarding configuring pipelines in Heroku, and distinct public/private S3 buckets in AWS.

Please read the documentation I’ve provided in those sections to ensure you are complying with best practices and procedures to keep your app safe and secure.

Prerequisites

Before you get started, make sure to have Node, Docker, and the Heroku CLI installed. You will also need to set up an…

OmbuLabs.ai 

Teaching an AI Scraper from Human Corrections

When we onboard a new event source, the system looks at a few sample events on the site and works out where each field lives on the page: title, description, date, time, price, image, venue, and ticket link. An admin then reviews the extracted samples before the source goes live. Sometimes a value is wrong. The extraction grabbed footer text instead of the event title, or pulled in a paragraph of extra text around a price, or found nothing at all.

The obvious fix is to let the admin edit the value and save it. That fixes the one event on the screen and nothing else, because the next event from the same site is still extracted by the same wrong rule. An edit is far more useful when we read…

Island94.org 

Bad requests and the dream of a quiet Rails app

I’ve kept a notebook page since, oh, 2013, of common exceptions I’ve encountered ever since I started building production Rails applications. It’s a big one.

When you put a web application on the internet, it’s going to get hit with a firehose of garbage requests: scanners and bots that are trying to discover malicious vulnerabilities, and scanners and bots trying to do something useful, like put your website in a search engine, but are built oddly.

And when you’re using an exception monitoring product like Sentry or AppSignal or whatever, as you should, you’re going to start being alerted to exceptions from this natural background noise of the firehose of garbage.

…

Evil Martians 

How to make postMessage type-safe in under 350 bytes

Authors: Pavel Grinchenko, Frontend Engineer, and Travis Turner, Tech EditorTopics: DX, Open Source, TypeScript, JavaScript

Typed-channel is a library for typed messages and requests across workers, iframes, tabs, and event buses.

typed-channel makes postMessage type-safe in about 350 bytes. You define message names and payloads once, and TypeScript checks both sides. The same API works across Web Workers, iframes, tabs, and in-page event buses. Version 0.11 adds cancelable requests: cancel a request, and its handler stops too.

Carmine Paolino 

Solco: Stop Preparing Your Tracks, Start Preparing Your Gigs

Some of you may not know this, but I’m a DJ in my free time. I founded Floppy Disco, a music collective to bring the magic of Disco and House to Berlin, and I’ve played clubs all over here and in other places in Europe. I love DJing, and my favourite part is finding new music and playing it for people.

Preparing my tracks, however, has never been truly fun. It rather felt like admin: fixing beat grids that were often wrong, fighting clunky software like rekordbox, building playlists by hand, correcting tags and genres, updating playlists, and deciding whether ratings or colours should stand for energy, mood or vocals.

So I said enough, and built Solco to do that work for me. Today it…

Tim Riley 

Continuations 2026/43: Perplexing inconsistency

  • Work continues on closing all our open parentheses in the lead-up to the next Hanami release.

  • I started this week fixing a regression in our body params logging. Thanks @Drowze for reporting it! In response to some good feedback from Paweł, I also filed an issue about possibly making body params logging a configurable thing in the future.

    While I was working in this space, I decided it was time we expanded Dry Logger’s log filtering, including substring matching and first-class regex support. This is close to being ready to go, I just need to reply to some good feedback on the PR from Michael.

  • Aaron voiced a perplexing inconsistency in how predicate functions are used as keyword…

The Ruby on Rails Podcast 

Episode 558: Background Batches with JP Camara

JP Camara joins the show to explore background job coordination, real-time collaboration, and the opportunities he sees for Ruby and Rails as AI changes how developers work.

First, JP shares the story behind bringing batches to Solid Queue, from an early proposal to the conference conversations and community interest that helped move the feature forward. He explains how batches let developers treat a group of jobs as a unit, track success and failure, and trigger callbacks when processing finishes—making it easier to coordinate workflows that span many background jobs.

JP also discusses the implementation challenges behind the feature, including database transactions, jobs…

RubyGems Blog 

4.1.0.beta3 Released

RubyGems and Bundler 4.1.0.beta3 include enhancements, bug fixes and features.

To update to the latest RubyGems you can run:

gem update --system [--pre]

To update to the latest Bundler you can run:

gem install bundler [--pre]
bundle update --bundler=4.1.0.beta3

Release Notes

RubyGems

Enhancements:
  • Installs bundler 4.1.0.beta3 as a default gem.
Bug fixes:
  • Skip executable removal gracefully when the bin directory is missing. Pull request #9963 by Evan Li and Hiroshi SHIBATA
  • Fix file locks letting multiple processes in when lock files are removed. Pull request #9930 by Richard Janita and Hiroshi SHIBATA
  • Turn off echo before printing the password prompt. Pull request #9969…

Bundler

Changes already released in 4.0.x are not repeated here.

Features:
  • Rename the from: and to: keys of override to in: and with:. Pull request #9979 by Hiroshi SHIBATA
  • Record overrides in Gemfile.lock (OVERRIDES…
Bug fixes:
  • Make Bundler::Source::Rubygems#hash agree with …
Planet Argon Blog 

Rails World: What Did our Software Delivery Manager get out of it?

Rails World: What Did our Software Delivery Manager get out of it?

Our Software Delivery Manager's thoughts on agent-ready Rails apps and project management after Rails World.

Continue Reading

OmbuLabs.ai 

1682 Conference: The PB&J Principle

On October 7, I attended the 1682 Conference in Philadelphia and got to hear many great speakers talk about how AI is changing customer experience. One talk that stuck with me was “The PB&J Principle: What every growing AI engine needs” by Mike Pitone from Wawa.

If you live anywhere near Philadelphia, you probably have a few Wawa memories. Maybe it’s coffee on the way to work, a late-night stop with friends, or grabbing hoagies before heading down the shore. After enough visits, you have an order you barely have to think about. Mine is the Meatball Parmesan hoagie.

What you might not know is how complicated a convenience store gets when orders come in from the counter, the kiosks, and…

Gusto Engineering - Medium 

How Spec-Driven Development Shaped My New Way of Engineering

Before adopting spec-driven development (SDD), I spent a lot of my time renegotiating with AI agents before we reached a plan I was happy with. Worse, without persisted artifacts or structured task tracking, agents would routinely suffer context window decay.

Illustration of a developer looking overwhelmed while surrounded by floating panels of code.

Without SDD, my AI-assisted work wasn’t leaving durable records of what had been implemented. When I iterated on an AI-implemented feature that was undocumented, it was hard to backtrack on the reasoning behind the code. Not to mention the hassle when picking up a task in a new session! Lastly, if I needed uncommitted, deleted code rewritten,…

The Rails Tech Debt Blog 

Making AI Agents Safe to Retry

Over in the OmbuLabs.ai blog, our post on the ReAct pattern in Ruby walked through building an agent that reasons about a task, calls tools, and acts on the results, all inside a single Ruby script. That’s fine for a command-line experiment. It’s a different story once that same agent needs to run inside a Rails app, triggered by a web request, where a multi-step reasoning loop can easily take longer than any request should stay open.

The obvious fix is to move the agent into a background job. Sidekiq already handles work that takes a while, so an agent’s loop of thinking, searching, and acting should fit right in. It does, mostly, but a job’s retry semantics were built around retrying a…

Radan Skorić's website 

"Make the change easy, then make the easy change" is a great way to code with AI

I firmly believe that we still need to read some of the code.1 It’s suboptimal to read all of the code, but I consider it irresponsible to read none of it. I won’t explain why now because that would fill several more articles. I just want to share this upfront because it clarifies where I’m coming from. But I am trying to be smart about it2, and I’ve found the quote in the title very useful: “...
Robby on Rails 

Rails, AI, Open Source, and Getting Too Old for Late-Night Punk Shows

I recently joined Errol Schmidt on his Tech for Humans podcast for a conversation about Ruby on Rails, AI, running a software consultancy, open source, and somehow… punk rock.

We started by revisiting my recent Rails World keynote and why I think engineers should spend more time improving the environments they work in. From there, we wandered into what it’s like running Planet Argon in an increasingly AI-assisted industry, why Rails upgrades keep getting postponed, and whether AI might change how we think about open source dependencies.

We also talked about my early days as an anarcho-punk kid experimenting with Linux, how that eventually led to starting a software consultancy, and why…

Paagman.dev 

How fast can you actually patch Ruby?

When I tried to update an app to Ruby 4.0.9 last Friday, the official Docker community image wasn’t available yet. The release fixed vulnerabilities GitLab had found, but I had to wait before I could deploy.

A few months ago, a government Rails site was hit by an ActiveStorage vulnerability eight hours after the patch went out. Last week, PHP2Shell was being exploited before it was announced.1 Waiting for a Docker image can eat up the time you have to respond.

When Ruby 4.0.9 became available

I took every installer and version manager listed on the official installation page on ruby-lang.org, then added container images, CI providers and hosting platforms I could think of. For each, I…

All…