mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-06 21:46:40 +02:00
Merge remote-tracking branch 'origin/main' into garrytan/openclaw-browser-ctrl
Resolved conflicts: - meta-commands.ts: kept our security pipeline (scope pre-validation + executeCommand callback) and integrated main's watch-mode blocking for chain write commands - server.ts: kept our !tunnelActive guard with security documentation over main's headed-mode detection approach - package.json: took main's version Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vendored
+2503
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
||||
import { describe, test, expect } from "bun:test";
|
||||
import { readFileSync } from "fs";
|
||||
import path from "path";
|
||||
|
||||
const SCRIPT = path.join(import.meta.dir, "..", "bin", "gstack-learnings-search");
|
||||
|
||||
describe("gstack-learnings-search injection prevention", () => {
|
||||
const script = readFileSync(SCRIPT, "utf-8");
|
||||
|
||||
test("no shell interpolation inside bun -e string", () => {
|
||||
// Extract the bun -e block (everything between `bun -e "` and the closing `"`)
|
||||
const bunBlock = script.slice(script.indexOf('bun -e "'));
|
||||
|
||||
// Should NOT contain ${VAR} patterns (shell interpolation)
|
||||
// These are RCE vectors: a malicious learnings entry with '; rm -rf / ;' in the
|
||||
// query field would execute arbitrary commands via shell interpolation.
|
||||
const shellInterpolations = bunBlock.match(/'\$\{[A-Z_]+\}'/g) || [];
|
||||
const bareInterpolations = bunBlock.match(/\$\{[A-Z_]+\}/g) || [];
|
||||
|
||||
// Filter out any that are inside process.env references (those are safe)
|
||||
const unsafeInterpolations = [
|
||||
...shellInterpolations,
|
||||
...bareInterpolations,
|
||||
].filter((m) => !m.includes("process.env"));
|
||||
|
||||
expect(unsafeInterpolations).toEqual([]);
|
||||
});
|
||||
|
||||
test("uses process.env for all user-controlled values", () => {
|
||||
const bunBlock = script.slice(script.indexOf('bun -e "'));
|
||||
|
||||
// Must use process.env for TYPE, QUERY, LIMIT, SLUG, CROSS_PROJECT
|
||||
expect(bunBlock).toContain("process.env.GSTACK_SEARCH_TYPE");
|
||||
expect(bunBlock).toContain("process.env.GSTACK_SEARCH_QUERY");
|
||||
expect(bunBlock).toContain("process.env.GSTACK_SEARCH_LIMIT");
|
||||
expect(bunBlock).toContain("process.env.GSTACK_SEARCH_SLUG");
|
||||
expect(bunBlock).toContain("process.env.GSTACK_SEARCH_CROSS");
|
||||
});
|
||||
|
||||
test("env vars are set on the bun command line", () => {
|
||||
// The env vars must be passed to bun, not just set in the shell
|
||||
expect(script).toContain("GSTACK_SEARCH_TYPE=");
|
||||
expect(script).toContain("GSTACK_SEARCH_QUERY=");
|
||||
expect(script).toContain("GSTACK_SEARCH_LIMIT=");
|
||||
expect(script).toContain("GSTACK_SEARCH_SLUG=");
|
||||
expect(script).toContain("GSTACK_SEARCH_CROSS=");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user