Skip to content

RI-8322: plugin command sandbox bypass via startsWith()#6227

Merged
pawelangelow merged 2 commits into
mainfrom
be/bugfix/RI-8322/plugin-command-sandbox-startswith
Jul 20, 2026
Merged

RI-8322: plugin command sandbox bypass via startsWith()#6227
pawelangelow merged 2 commits into
mainfrom
be/bugfix/RI-8322/plugin-command-sandbox-startswith

Conversation

@pawelangelow

@pawelangelow pawelangelow commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

What

The Workbench plugin command sandbox validates commands against a whitelist of
read-only commands, but enforcement used targetCommand.startsWith(command).
Because get is whitelisted, prefix matches like GETDEL (reads + deletes),
GETEX (modifies TTL), and GETSET (reads + overwrites) passed the check
despite not being whitelisted — letting a read-only plugin execute destructive
operations and breaking the sandbox trust boundary.

Changes

  • Replace the prefix startsWith matcher with an exact command-word match:
    compare commandLine.toLowerCase().split(' ')[0] against the whitelist using
    .includes(...). get foo still passes; getdel foo no longer does.
  • Casing is handled (both sides lowercased) and multi-word command lines resolve
    to their first token.
  • Add tests asserting GETDEL/GETEX/GETSET are rejected while GET (any
    casing) is allowed.
  • Typed the spec's mock provider/executor holders, which cleared 14 pre-existing
    implicit-any type errors; refreshed the API .tscheck.rec.json baseline
    accordingly (net decrease).

Note

High Risk
This is a security fix on plugin command authorization; incorrect matching could still allow destructive Redis commands from plugins or break legitimate read-only plugin behavior.

Overview
Fixes a plugin command sandbox bypass where whitelist checks used startsWith, so commands like GETDEL, GETEX, and GETSET could pass when get was allowed.

checkWhitelistedCommands now takes the first token via splitCliCommandLine (same as the workbench executor), lowercases it, and requires an exact whitelist.includes match instead of a prefix match. Legitimate GET (any casing, tab/space delimiters) still runs; prefix lookalikes are rejected before sendCommand.

Adds parameterized unit tests for those cases and tightens plugins.service.spec.ts mock typing; drops the corresponding entries from .tscheck.rec.json.

Reviewed by Cursor Bugbot for commit d6587ce. Bugbot is set up for automated code reviews on this repo. Configure here.

The plugin command sandbox matched the command line against the
read-only whitelist with startsWith(). Because "get" is whitelisted,
GETDEL/GETEX/GETSET passed the check and let read-only plugins run
destructive operations. Match the first command word exactly instead.

Fixes #RI-8322

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pawelangelow pawelangelow self-assigned this Jul 17, 2026
@pawelangelow
pawelangelow requested a review from a team as a code owner July 17, 2026 09:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7aa220db67

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread redisinsight/api/src/modules/workbench/plugins.service.ts Outdated
@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Code Coverage - Backend unit tests

St.
Category Percentage Covered / Total
🟢 Statements 93.14% 16505/17721
🟡 Branches 75.32% 5277/7006
🟢 Functions 87.46% 2532/2895
🟢 Lines 92.99% 15783/16972

Test suite run success

3692 tests passing in 321 suites.

Report generated by 🧪jest coverage report action from d6587ce

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Code Coverage - Integration Tests

Status Category Percentage Covered / Total
🟡 Statements 79.26% 18212/22977
🟡 Branches 61.89% 8490/13717
🟡 Functions 66.89% 2461/3679
🟡 Lines 78.86% 17147/21742

Addresses PR review: derive the command word with splitCliCommandLine
(same parser the executor uses) instead of split(' '), so validation and
execution agree on non-space delimiters (tab/newline/CR/NUL) and quoting.
Unparseable input stays rejected (fail closed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pawelangelow
pawelangelow merged commit a05d057 into main Jul 20, 2026
29 checks passed
@pawelangelow
pawelangelow deleted the be/bugfix/RI-8322/plugin-command-sandbox-startswith branch July 20, 2026 06:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants