Project releases
Ruflo 3.46.1 security fix: Windows browser tools no longer pass input through a shell
On Windows machines without a global agent-browser install, Ruflo's browser MCP tools fell back to npx through the command shell, so text supplied to the tools could be read as shell syntax. Release 3.46.1 on September 26 starts the process directly with an argument list and fails closed. It closes a week that also shipped four feature and fix releases, summarised here.
GitHub activity: · Published:
What this is about
Ruflo gives AI agents a set of browser tools over MCP: open a page, fill a field, type, run a script in the page. Those tools hand the actual work to a helper program called agent-browser. If agent-browser is not installed globally, Ruflo falls back to fetching it with npx.
On Windows, that fallback was started through the command shell, which is how Windows finds npx. The problem is that the values an agent passes to the tools, such as the text to fill in, a selector or a script, travelled on that same command line. A shell reads special characters as instructions, so a value could be interpreted as a command rather than as text.
What changed
Release v3.46.1 was published on September 26 from pull request #3451, merge commit a5adb5aa. The release notes state the scope precisely:
- Affected: Windows hosts using the browser_* tools where agent-browser is not installed globally, on every published version carrying the earlier npx fallback, including 3.46.0.
- Not affected: macOS and Linux.
- Fix: the launcher resolves the npm shim to the real program behind it and starts it with an argument list. No shell is involved. If it cannot resolve the program without a shell, the tool reports the install hint instead of falling back to one.
- Audit: the other places that set a shell option on Windows (init, eject, agentbbs) were checked; none receives tool-supplied input.
- Tests: 17 new tests drive the tools with shell metacharacters on simulated Windows and Linux and assert each value arrives as one literal argument. They fail on the old code. A static guard fails if a shell option is reintroduced in the browser tools.
The decision and the alternatives considered are recorded in ADR-401. The pull request also records a known gap honestly: the full command-line suite at merge time showed 4,024 passing and 9 failing tests, which the author describes as outside this change.
The rest of the week in one place
Ruflo shipped five releases between September 23 and 26. Rather than a thin article per version, here is what each one changed, from its own release notes:
- 3.43.0 (Sept 23): a bug in the vector index library meant clustered data had no links between clusters. In the release's own measurement of 3,000 items in 20 groups, correct top-10 matches went from about 7 in 100 to 100 in 100. Several operations that failed while reporting success now report the failure.
- 3.44.0 (Sept 23): the installed router.js agent picker now updates itself from a signed file list, so the 3.43.0 matching fix actually reaches existing installs. An optional model-based picker was added and measured; it did not meet the bar, so the default is unchanged.
- 3.45.0 (Sept 24): the CLI pins one exact memory package version so upgrades can no longer leave a stale copy behind, and ruflo doctor --component memory-package warns if they differ.
- 3.46.0 (Sept 26): 29 reviewed pull requests merged together, including MCP policy enforcement being skipped by the shipped stdio launchers, memory upsert collisions deleting distinct entries, and witness verify --strict.
The 3.46.0 batch is a real set of fixes, but it is a collection of small ones and it is superseded for Windows browser users by 3.46.1, so it is covered here rather than as its own story.
Get started
Prerequisites: Node.js 22 or later and a terminal.
npx ruflo@latest --version
Expected result: a version string. At the time of checking, the registry's latest tag pointed at 3.47.0, published September 27, which is later than the fix. Anything at 3.46.1 or above carries it. If you must stay on an older version, the release notes give a workaround that avoids the fallback path:
npm i -g agent-browser
Register Ruflo as an MCP server in Claude Code with the command documented in the repository:
claude mcp add claude-flow -- npx ruflo@latest mcp start
Commands here were read from the release notes and repository documentation at the pinned reference; they were not executed as part of writing this article.
The ruflo wrapper still accepts older cached CLI versions (tracked as #3306 in the 3.45.0 notes), so check the printed version rather than assuming @latest resolved to the newest build.
Use it today
Practical case: a team runs agents on Windows laptops that fill in web forms from ticket text. Input is untrusted ticket text. The workflow passes it to browser_fill. Before this release, on a machine without agent-browser installed globally, characters in that text could be interpreted by the shell. After it, the text is delivered to the browser helper as a single literal argument.
Reader acceptance test: on an upgraded Windows machine without agent-browser installed globally, fill a test field with a value containing an ampersand followed by a harmless word. The field should contain the full literal string, and no separate command should run.
Push it further
Experimental commentary. The fail-closed choice matters more than the patch itself. A launcher that cannot find a safe path and says so is easier to reason about than one that silently tries something less safe. The same pattern could apply to every place an agent tool shells out.
Limitation: this fixes one execution path on one operating system. It does not validate what an agent chooses to type into a page. Depends on 3.46.1 or later actually being the version that runs. Falsifiable test: search the browser tools source at the release tag for a shell option. The static guard claims there is none; finding one would contradict the release.
Read the original on GitHub release
Release v3.46.1 — Windows browser MCP tool shell fix (PR #3451, merge commit a5adb5aa, ADR-401)