Skip to content

Commit 418eed5

Browse files
committed
harden: add 8 MiB frame limit + Section 23 guardrail (v0.2.7)
- Add MAX_CONTENT_LENGTH_BYTES to MCP stdio transport - Reject oversized Content-Length with explicit error - Add Section 23 guardrail enforcing hardening in source
1 parent 8ea7474 commit 418eed5

6 files changed

Lines changed: 40 additions & 11 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ members = [
99
exclude = ["npm/wasm"]
1010

1111
[workspace.package]
12-
version = "0.2.6"
12+
version = "0.2.7"
1313
edition = "2021"
1414
license = "MIT"
1515
repository = "https://github.com/agentralabs/agentic-codebase"
@@ -19,7 +19,7 @@ authors = ["Agentra Labs <contact@agentralabs.tech>"]
1919
[package]
2020
default-run = "acb"
2121
name = "agentic-codebase"
22-
version = "0.2.6"
22+
version = "0.2.7"
2323
edition = "2021"
2424
license = "MIT"
2525
repository = "https://github.com/agentralabs/agentic-codebase"

crates/agentic-codebase-cli/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "agentic-codebase-cli"
3-
version = "0.2.6"
3+
version = "0.2.7"
44
edition = "2021"
55
license = "MIT"
66
repository = "https://github.com/agentralabs/agentic-codebase"
@@ -15,6 +15,6 @@ name = "acb"
1515
path = "src/main.rs"
1616

1717
[dependencies]
18-
agentic-codebase = { path = "../..", version = "0.2.6" }
18+
agentic-codebase = { path = "../..", version = "0.2.7" }
1919
clap = { version = "4", features = ["derive"] }
2020
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

crates/agentic-codebase-ffi/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "agentic-codebase-ffi"
3-
version = "0.2.6"
3+
version = "0.2.7"
44
edition = "2021"
55
license = "MIT"
66
repository = "https://github.com/agentralabs/agentic-codebase"
@@ -14,7 +14,7 @@ categories = ["api-bindings"]
1414
crate-type = ["cdylib", "rlib"]
1515

1616
[dependencies]
17-
agentic-codebase = { path = "../..", version = "0.2.6" }
17+
agentic-codebase = { path = "../..", version = "0.2.7" }
1818
pyo3 = { version = "0.20", features = ["extension-module"], optional = true }
1919
wasm-bindgen = { version = "0.2", optional = true }
2020
serde-wasm-bindgen = { version = "0.6", optional = true }

crates/agentic-codebase-mcp/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "agentic-codebase-mcp"
3-
version = "0.2.6"
3+
version = "0.2.7"
44
edition = "2021"
55
license = "MIT"
66
repository = "https://github.com/agentralabs/agentic-codebase"
@@ -15,7 +15,7 @@ name = "agentic-codebase-mcp"
1515
path = "src/main.rs"
1616

1717
[dependencies]
18-
agentic-codebase = { path = "../..", version = "0.2.6", features = ["stdio"] }
18+
agentic-codebase = { path = "../..", version = "0.2.7", features = ["stdio"] }
1919
clap = { version = "4", features = ["derive"] }
2020
sha2 = "0.10"
2121
walkdir = "2"

crates/agentic-codebase-mcp/src/main.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ fn run_stdio(graph_path: Option<&str>, graph_name: Option<String>) {
151151
run_stdio_loop(&mut reader, &mut stdout, &mut server, &mut ghost);
152152
}
153153

154+
/// Hard limit for framed stdio payloads (8 MiB).
155+
const MAX_CONTENT_LENGTH_BYTES: usize = 8 * 1024 * 1024;
156+
154157
fn run_stdio_loop<R: BufRead + Read, W: Write>(
155158
reader: &mut R,
156159
writer: &mut W,
@@ -180,8 +183,17 @@ fn run_stdio_loop<R: BufRead + Read, W: Write>(
180183
if lower.starts_with("content-length:") {
181184
let rest = trimmed.split_once(':').map(|(_, rhs)| rhs).unwrap_or("");
182185
match rest.trim().parse::<usize>() {
183-
Ok(n) => content_length = Some(n),
184-
Err(_) => content_length = None,
186+
Ok(n) if n <= MAX_CONTENT_LENGTH_BYTES => content_length = Some(n),
187+
Ok(n) => {
188+
eprintln!(
189+
"Content-Length {n} exceeds max frame size of {MAX_CONTENT_LENGTH_BYTES} bytes"
190+
);
191+
break;
192+
}
193+
Err(_) => {
194+
eprintln!("Invalid Content-Length header: {trimmed}");
195+
content_length = None;
196+
}
185197
}
186198
continue;
187199
}

scripts/check-canonical-sister.sh

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ FRONTMATTER_EXTRA=(
1616
)
1717
# ── End sister-specific configuration ────────────────────────────────────────
1818

19-
2019
# ── Shared helpers ───────────────────────────────────────────────────────────
2120

2221
fail() {
@@ -323,6 +322,24 @@ assert_file "python/pyproject.toml"
323322
assert_dir "npm/wasm"
324323
assert_file "npm/wasm/Cargo.toml"
325324

325+
# ── 23. MCP stdio hardening (Section 13 enforcement) ────────────────────────
326+
# Every sister's MCP server must enforce:
327+
# - 8 MiB frame size limit (MAX_CONTENT_LENGTH_BYTES)
328+
# - Content-Length framing support
329+
# - JSON-RPC version validation ("2.0")
330+
331+
MCP_SRC="crates/agentic-${SISTER_KEY}-mcp/src"
332+
assert_dir "$MCP_SRC"
333+
334+
# 8 MiB frame limit constant must exist in MCP server source
335+
assert_contains "MAX_CONTENT_LENGTH_BYTES" "$MCP_SRC"
336+
337+
# Content-Length header parsing must exist
338+
assert_contains "content-length:" "$MCP_SRC"
339+
340+
# JSON-RPC 2.0 version must be validated (reject non-2.0)
341+
assert_contains 'jsonrpc' "$MCP_SRC"
342+
326343
# ── Done ────────────────────────────────────────────────────────────────────
327344

328345
echo "Canonical sister guardrails passed."

0 commit comments

Comments
 (0)