AID-H-034.003: Server-Side Tool Invocation Validation & Object-Level Authorization
Pillars: app, infra, data
Lifecycle: building, operation
Scope boundary
Owns final server-handler schema validation and per-tool, object, tenant, and backend authorization before reads, calls, queries, fetches, filesystem access, commands, or code execution. It enforces the server's own trust boundary after request arrival.
AID-H-018.002: AID-H-034.003 authorizes the MCP request inside the handler against MCP-local tools, tenants, backends, and objects; AID-H-018.002 owns authorization at an external non-MCP application or service boundary. An MCP handler may consume an external service's decision without scoring the same external-object authorization twice, but it still enforces its own MCP request boundary.
AID-H-019.001: AID-H-034.003 authorizes whether a URL-fetching tool may perform the requested operation; AID-H-019.001 normalizes, resolves, pins, bounds, and safely fetches the destination. Authorization to fetch does not make the URL network-safe.
AID-I-001: AID-H-034.003 validates and authorizes command or code paths in the MCP handler; AID-I-001 contains the execution environment when such paths are permitted. Handler checks do not create process isolation.
AID-H-018.009: AID-H-034.003 validates the MCP tool request and consumes a filesystem-broker receipt before a handler uses a workspace, working directory, interpreter, script, module, executable, or other model-influenced path; AID-H-018.009 owns rooted object resolution, path confinement, race resistance, and exact-object evidence. The MCP handler must not replay path-traversal or symlink fixtures as a second confinement PASS.
Implementation guidance
- AID-H-034.003-G001: Validate every tools/call argument with a strict server-side JSON Schema before invoking the handler.
- AID-H-034.003-G002: Bind each tool invocation to the authenticated principal, per-request client metadata, tenant, explicit application handles, and backend object authorization before executing side effects.
- AID-H-034.003-G003: Use parameterized SQL or NoSQL APIs and server-side identifier allowlists for every database-backed MCP tool.
- AID-H-034.003-G004: For tools that fetch URLs or resolve network targets, enforce SSRF-safe URL validation, redirect validation, DNS rebinding checks, and egress allowlists.
- AID-H-034.003-G005: For command, code, browser, and filesystem tools, deny shell execution by default, consume AID-H-018.009 filesystem-broker receipts instead of caller paths, and route permitted handlers through sandboxed execution profiles.
AID-H-034.003-G001
Concept:
Tool schemas are not just client hints. They are server-side contracts. The MCP server must reject unknown fields, wrong types, missing required values, oversized values, invalid enums, and unsafe string formats before the handler runs.
Example strict schema validation with Ajv
// file: src/tools/schemaGate.js
import Ajv2020 from "ajv/dist/2020.js";
import addFormats from "ajv-formats";
const ajv = new Ajv2020({
allErrors: true,
strict: true,
removeAdditional: false,
coerceTypes: false,
useDefaults: false
});
addFormats(ajv);
const schemas = {
read_customer_account: {
type: "object",
additionalProperties: false,
required: ["customer_id"],
properties: {
customer_id: {
type: "string",
pattern: "^cus_[A-Za-z0-9]{12,32}$"
}
}
}
};
const validators = Object.fromEntries(
Object.entries(schemas).map(([name, schema]) => [name, ajv.compile(schema)])
);
export function validateToolArguments(toolName, args) {
const validate = validators[toolName];
if (!validate) {
throw new Error("Unknown tool: " + toolName);
}
if (!validate(args)) {
const safeDetail = (validate.errors || []).map(error => ({
field: error.instancePath || "/",
constraint: error.keyword
}));
throw new Error("Invalid tool arguments: " + JSON.stringify(safeDetail));
}
return args;
}
Operational notes: Use explicit maximum lengths, numeric ranges, enum values, URL schemes, and file path formats. Do not use schema descriptions as enforcement; descriptions are model-visible documentation, not policy. Return field and constraint names only in validation errors; never echo raw argument values into model-visible tool errors.
Verify safely
A separately credentialed verifier independently recompiles each schema and replays valid, missing, extra, wrong-type, duplicate-key, deep, oversized, pathological-regex, external-reference, schema-drift and validator-outage fixtures through the deployed dispatcher.
AID-H-034.003-G002
Concept:
The server should not assume the client only calls tools it is allowed to use. The handler must verify that the authenticated user or workload can access the specific backend object or tenant being requested.
Example object-level authorization check
// file: src/tools/customerAuthz.js
export async function requireCustomerAccess({ auth, customerId, db }) {
const tenantIds = Array.isArray(auth.tenantIds) ? auth.tenantIds : [];
const scopes = new Set(Array.isArray(auth.scopes) ? auth.scopes : []);
if (!auth.subject || tenantIds.length === 0) {
throw new Error("Missing authenticated tenant context");
}
const row = await db.queryOne(
"select tenant_id from customers where customer_id = ?",
[customerId]
);
if (!row) {
throw new Error("Customer not found");
}
const allowed = tenantIds.includes(row.tenant_id) &&
scopes.has("customers:read");
if (!allowed) {
throw new Error("Not authorized for customer");
}
return row;
}
export async function readCustomerAccountHandler({ auth, args, db }) {
await requireCustomerAccess({ auth, customerId: args.customer_id, db });
return db.queryOne(
"select customer_id, status, plan from customers where customer_id = ?",
[args.customer_id]
);
}
Operational notes: Treat the MCP server as the final policy enforcement point. AID-H-018 can prevent the agent from selecting a capability, but this server-side gate prevents direct API calls, compromised clients, stale client policy, or cross-tenant confusion from reaching backend data.
Verify safely
A separately credentialed verifier replays IDOR, cross-tenant, subject/client swap, forged/expired/revoked handle, object-version race, stale grant, confused-deputy and retry fixtures against real authorization and backend boundaries.
AID-H-034.003-G003
Concept:
JSON Schema validates shape; it does not make a database query safe. Tool arguments can be influenced by indirect prompt injection, malicious clients, or compromised sessions. Treat every argument as untrusted data and never concatenate it into SQL, MongoDB filters, sort clauses, collection names, table names, or projection expressions.
Example SQL handler
// file: src/tools/customerSearchSql.js
const allowedSortColumns = {
created_at: "created_at",
customer_id: "customer_id"
};
export async function searchCustomers({ auth, args, db }) {
if (!auth.scopes.includes("customers:read")) {
throw new Error("Missing customers:read scope");
}
const sortColumn = allowedSortColumns[args.sort_by || "created_at"];
if (!sortColumn) {
throw new Error("Unsupported sort column");
}
return db.query(
"select customer_id, status, plan from customers where tenant_id = ? and email like ? order by " +
sortColumn +
" limit ?",
[auth.activeTenantId, "%" + args.email_fragment + "%", Math.min(args.limit || 25, 100)]
);
}
Example MongoDB filter construction
// file: src/tools/customerSearchMongo.js
const allowedFields = new Set(["customer_id", "email", "status"]);
export async function findCustomerByField({ auth, args, collection }) {
if (!allowedFields.has(args.field)) {
throw new Error("Unsupported field");
}
return collection.findOne(
{
tenant_id: auth.activeTenantId,
[args.field]: String(args.value)
},
{
projection: { _id: 0, customer_id: 1, status: 1, plan: 1 }
}
);
}
Operational notes: Give each MCP server or tool a least-privilege database identity, preferably read-only for read tools. Dynamic identifiers require server-owned enum allowlists; prepared statements only protect values, not table names, column names, collection names, or sort expressions.
Verify safely
A separately credentialed verifier captures datastore-side statement templates and bindings while testing quote/comment/encoding, identifier, operator, stacked-query, wildcard, cross-tenant, timeout and over-result injection fixtures.
AID-H-034.003-G004
Concept:
URL-fetching MCP tools are high-risk because attackers can use them as server-side probes into internal networks, cloud metadata services, localhost admin panels, or private DNS names. This guidance references AID-I-002 for network segmentation and AID-H-019.001 for safe-fetch patterns.
Example URL validation in Python
# File: tools/safe_fetch_gate.py
from __future__ import annotations
import ipaddress
import math
import socket
from urllib.parse import urlparse
import urllib3
BLOCKED_HOSTS = {"localhost", "metadata.google.internal"}
ALLOWED_SCHEMES = {"https"}
ALLOWED_DOMAINS = {"api.github.com", "docs.example.com"}
METADATA_IPS = {
ipaddress.ip_network("169.254.169.254/32"),
ipaddress.ip_network("169.254.169.253/32"),
ipaddress.ip_network("100.100.100.200/32"),
}
def normalize_ip(ip):
if isinstance(ip, ipaddress.IPv6Address) and ip.ipv4_mapped:
return ip.ipv4_mapped
return ip
def is_blocked_ip(ip) -> bool:
normalized = normalize_ip(ip)
if not normalized.is_global:
return True
return any(normalized in network for network in METADATA_IPS)
def domain_allowed(hostname: str) -> bool:
return any(hostname == domain or hostname.endswith("." + domain) for domain in ALLOWED_DOMAINS)
def _all_resolved_ips(hostname: str):
infos = socket.getaddrinfo(hostname, None, proto=socket.IPPROTO_TCP)
ips = []
for info in infos:
sockaddr = info[4]
candidate = normalize_ip(ipaddress.ip_address(sockaddr[0]))
if is_blocked_ip(candidate):
raise ValueError(f"Blocked non-public or metadata address: {candidate}")
ips.append(str(candidate))
return ips
def parse_and_pin_url(url: str):
parsed = urlparse(url)
if parsed.scheme not in ALLOWED_SCHEMES:
raise ValueError("Only https URLs are allowed")
if not parsed.hostname:
raise ValueError("URL hostname is required")
if parsed.username is not None or parsed.password is not None or parsed.fragment:
raise ValueError("Userinfo and fragments are not allowed in fetch URLs")
if parsed.port not in {None, 443}:
raise ValueError("Only TCP port 443 is allowed")
hostname = parsed.hostname.encode("idna").decode("ascii").lower().rstrip(".")
if hostname in BLOCKED_HOSTS:
raise ValueError("Localhost is blocked")
if not domain_allowed(hostname):
raise ValueError("Domain is not on the fetch allowlist")
try:
literal = normalize_ip(ipaddress.ip_address(hostname))
except ValueError:
literal = None
if literal is not None:
raise ValueError("Use allowlisted hostnames, not literal IP addresses")
ips = _all_resolved_ips(hostname)
if not ips:
raise ValueError("No DNS answers")
return parsed._replace(netloc=hostname), ips[0]
def fetch_resolved_once(url: str, timeout: float, maximum_response_bytes: int) -> bytes:
if not math.isfinite(timeout) or timeout <= 0:
raise ValueError("signed fetch timeout must be finite and positive")
if isinstance(maximum_response_bytes, bool) or not isinstance(maximum_response_bytes, int) or maximum_response_bytes <= 0:
raise ValueError("signed response cap must be a positive integer")
parsed, ip_address = parse_and_pin_url(url)
target = parsed.path or "/"
if parsed.query:
target += "?" + parsed.query
pool = urllib3.HTTPSConnectionPool(
ip_address,
port=443,
server_hostname=parsed.hostname,
assert_hostname=parsed.hostname,
cert_reqs="CERT_REQUIRED",
timeout=timeout,
retries=False,
)
response = pool.request(
"GET",
target,
headers={"Host": parsed.hostname, "User-Agent": "AIDEFEND-MCP-Fetcher/1.0"},
redirect=False, preload_content=False, decode_content=True,
)
try:
if 300 <= response.status < 400:
raise ValueError("Redirects are disabled; validate each hop explicitly")
if response.status >= 400:
raise RuntimeError(f"Upstream fetch failed: {response.status}")
declared = response.headers.get("Content-Length")
if declared is not None and (not declared.isdigit() or int(declared) > maximum_response_bytes):
raise ValueError("Upstream response exceeds signed byte cap")
body = bytearray()
while True:
chunk = response.read(
amt=min(65536, maximum_response_bytes + 1 - len(body)),
decode_content=True,
)
if not chunk:
break
body.extend(chunk)
if len(body) > maximum_response_bytes:
raise ValueError("Decoded upstream response exceeds signed byte cap")
return bytes(body)
finally:
response.close()
pool.close()
Pass both timeout and maximum_response_bytes from the signed, versioned fetch policy for the specific tool and destination class.
Operational requirements
- Validate the initial URL and every redirect target; safest default is redirects disabled.
- Prefer egress allowlists and production egress proxies such as Smokescreen for tools that fetch arbitrary URLs.
- Block cloud metadata endpoints, link-local ranges, loopback, private ranges, IPv4-mapped IPv6 forms, and provider-specific metadata hostnames in code, not prose.
- Pin the resolved address for the actual connection, preserving the original hostname for SNI and Host, or place the fetcher behind an egress proxy that enforces DNS and IP policy.
Verify safely
A separately credentialed verifier tests mixed encodings, IPv4/IPv6 variants, localhost/private/link-local/metadata, allowlist suffix tricks, DNS rebinding between validation and connect, redirect chains, proxy bypass, wrong TLS identity, oversized/slow responses, and resolver/egress outages.
AID-H-034.003-G005
Keep caller-controlled paths out of the MCP handler
A command-capable MCP tool may accept an allowlisted command identifier and an opaque workspace handle, but it must never accept or pass a caller-supplied cwd, executable path, script path, or module path to a local process launcher. Send the opaque handle and authorization receipt to the filesystem broker owned by AID-H-018.009. That broker resolves the workspace from authenticated root policy, binds the operation to the exact filesystem objects, and returns a signed confinement receipt. This handler owns MCP request validation and receipt consumption; it does not earn a second filesystem-confinement outcome.
Use a fixed mTLS broker and verify its signed receipt
// File: src/tools/commandRunner.js
import { createHash, createPublicKey, randomUUID, verify } from "node:crypto";
import { readFileSync } from "node:fs";
import { request } from "node:https";
const COMMANDS = new Set(["git_status", "npm_audit_json"]);
const WORKSPACE_HANDLE = /^wsp_[A-Za-z0-9_-]{20,128}$/;
const OPAQUE_RECEIPT = /^[A-Za-z0-9._~-]{43,8192}$/;
const SHA256 = /^[a-f0-9]{64}$/;
const ED25519_SIGNATURE_B64 = /^[A-Za-z0-9+/]{86}==$/;
const BROKER = new URL(process.env.WORKSPACE_BROKER_URL);
if (
BROKER.protocol !== "https:" || BROKER.username || BROKER.password ||
BROKER.search || BROKER.hash || BROKER.pathname !== "/v1/workspace/execute"
) {
throw new Error("WORKSPACE_BROKER_URL must be the fixed canonical HTTPS broker endpoint");
}
function positiveNumber(name) {
const value = Number(process.env[name]);
if (!Number.isFinite(value) || value <= 0) throw new Error(name + " must be positive");
return value;
}
const TIMEOUT_MS = positiveNumber("WORKSPACE_BROKER_TIMEOUT_MS");
const MAX_RESPONSE_BYTES = positiveNumber("WORKSPACE_BROKER_MAX_RESPONSE_BYTES");
const MAX_STDOUT_BYTES = positiveNumber("WORKSPACE_BROKER_MAX_STDOUT_BYTES");
const MAX_RECEIPT_AGE_SECONDS = positiveNumber("WORKSPACE_BROKER_RECEIPT_MAX_AGE_SECONDS");
const MAX_FUTURE_SKEW_SECONDS = positiveNumber("WORKSPACE_BROKER_MAX_FUTURE_SKEW_SECONDS");
const TLS = {
ca: readFileSync("/etc/aidefend/workspace-broker/ca.pem"),
cert: readFileSync("/etc/aidefend/workspace-broker/client-cert.pem"),
key: readFileSync("/etc/aidefend/workspace-broker/client-key.pem"),
servername: BROKER.hostname,
rejectUnauthorized: true,
};
const RECEIPT_KEY = createPublicKey(
readFileSync("/etc/aidefend/workspace-broker/receipt-ed25519.pub.pem"),
);
function canonicalReceipt(receipt) {
const ordered = Object.fromEntries(
Object.entries(receipt).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0),
);
return Buffer.from(JSON.stringify(ordered), "utf8");
}
function postBroker(body) {
const encoded = Buffer.from(JSON.stringify(body), "utf8");
if (encoded.length > 16384) throw new Error("broker request exceeds hard byte cap");
return new Promise((resolve, reject) => {
const req = request({
protocol: BROKER.protocol,
hostname: BROKER.hostname,
port: BROKER.port || 443,
path: BROKER.pathname,
method: "POST",
...TLS,
headers: {
"content-type": "application/json",
"accept": "application/json",
"content-length": encoded.length,
},
}, response => {
response.on("error", reject);
const contentLength = response.headers["content-length"];
if (contentLength !== undefined) {
const declared = Number(contentLength);
if (!Number.isSafeInteger(declared) || declared < 0 || declared > MAX_RESPONSE_BYTES) {
response.destroy(new Error("broker response has an invalid declared length"));
return;
}
}
const chunks = [];
let size = 0;
response.on("data", chunk => {
size += chunk.length;
if (size > MAX_RESPONSE_BYTES) {
response.destroy(new Error("broker response exceeds streamed byte cap"));
return;
}
chunks.push(chunk);
});
response.on("end", () => {
if (response.statusCode !== 200) {
reject(new Error("workspace broker returned HTTP " + response.statusCode));
return;
}
try {
resolve(JSON.parse(Buffer.concat(chunks).toString("utf8")));
} catch (error) {
reject(new Error("workspace broker returned invalid JSON", { cause: error }));
}
});
});
req.setTimeout(TIMEOUT_MS, () => req.destroy(new Error("workspace broker timed out")));
req.on("error", reject);
req.end(encoded);
});
}
export async function runAllowedCommand({ commandId, workspaceHandle, authorizationReceipt }) {
if (!COMMANDS.has(commandId)) throw new Error("command is not allowlisted");
if (!WORKSPACE_HANDLE.test(workspaceHandle)) throw new Error("workspace handle is invalid");
if (!OPAQUE_RECEIPT.test(authorizationReceipt)) throw new Error("authorization receipt is invalid");
const requestId = randomUUID();
const response = await postBroker({
schema_version: "aidefend.workspace-broker-request.v1",
request_id: requestId,
command_id: commandId,
workspace_handle: workspaceHandle,
authorization_receipt: authorizationReceipt,
});
const expectedResponseKeys = ["receipt", "receipt_signature_b64", "schema_version", "stdout_utf8"];
if (
!response || typeof response !== "object" || Array.isArray(response) ||
JSON.stringify(Object.keys(response).sort()) !== JSON.stringify(expectedResponseKeys)
) throw new Error("workspace broker response schema differs");
if (response.schema_version !== "aidefend.workspace-broker-response.v1") {
throw new Error("workspace broker response version differs");
}
const receipt = response.receipt;
const expectedReceiptKeys = [
"authorization_receipt_sha256", "command_id", "control", "exit_code", "expires_at",
"issued_at", "object_identity_sha256", "outcome", "policy_sha256",
"request_id", "stderr_sha256", "stdout_sha256", "workspace_handle",
];
if (
!receipt || typeof receipt !== "object" || Array.isArray(receipt) ||
JSON.stringify(Object.keys(receipt).sort()) !== JSON.stringify(expectedReceiptKeys)
) throw new Error("filesystem broker receipt schema differs");
if (typeof response.receipt_signature_b64 !== "string" || !ED25519_SIGNATURE_B64.test(response.receipt_signature_b64)) {
throw new Error("filesystem broker receipt signature encoding is invalid");
}
const signature = Buffer.from(response.receipt_signature_b64, "base64");
if (!verify(null, canonicalReceipt(receipt), RECEIPT_KEY, signature)) {
throw new Error("filesystem broker receipt signature is invalid");
}
const now = Date.now();
const issuedAt = Date.parse(receipt.issued_at);
const expiresAt = Date.parse(receipt.expires_at);
if (
!Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) ||
issuedAt > now + MAX_FUTURE_SKEW_SECONDS * 1000 ||
now - issuedAt > MAX_RECEIPT_AGE_SECONDS * 1000 || expiresAt < issuedAt || expiresAt < now
) throw new Error("filesystem broker receipt is stale or future-dated");
const authorizationDigest = createHash("sha256").update(authorizationReceipt, "utf8").digest("hex");
const stdout = Buffer.from(response.stdout_utf8, "utf8");
if (
receipt.control !== "AID-H-018.009" || receipt.outcome !== "PASS" || receipt.exit_code !== 0 ||
receipt.request_id !== requestId || receipt.command_id !== commandId ||
receipt.workspace_handle !== workspaceHandle || stdout.length > MAX_STDOUT_BYTES ||
receipt.authorization_receipt_sha256 !== authorizationDigest ||
!SHA256.test(receipt.policy_sha256) || !SHA256.test(receipt.object_identity_sha256) ||
!SHA256.test(receipt.stdout_sha256) || !SHA256.test(receipt.stderr_sha256) ||
createHash("sha256").update(stdout).digest("hex") !== receipt.stdout_sha256
) throw new Error("filesystem broker receipt binding differs");
return {
stdout: response.stdout_utf8,
confinement_receipt_sha256: createHash("sha256").update(canonicalReceipt(receipt)).digest("hex"),
};
}
Deployment and verification
Provision the broker URL, mTLS material, Ed25519 receipt key, and numeric limits from a signed deployment profile; keep every key path root-owned and non-writable by the MCP service identity. The broker, not this handler, maps the opaque handle to an approved root, resolves the command's executable and working directory without following attacker-controlled links, executes inside the required AID-I-001 sandbox profile, and signs the exact-object receipt.
Exercise unknown command, forged or stale authorization receipt, cross-workspace handle replay, wrong request ID, altered stdout, bad receipt signature, expired receipt, oversized response, broker timeout, direct-handler bypass, traversal, symlink, reparse-point, mount, executable-substitution, and replacement-race fixtures. The filesystem fixtures are scored by AID-H-018.009; this guidance verifies only that every applicable MCP handler rejects bypass and consumes a valid receipt before returning data.
Open-source tools
- Ajv
- Pydantic
- Open Policy Agent (OPA)
- Cedar
- gVisor
- Firecracker
- Semgrep
- Zod (TypeScript argument-schema validation only; external object authorization required)
Commercial / hosted tools
- Snyk Code (pre-release SAST verification only)
- Checkmarx One (pre-release SAST verification only)
- Aqua Platform (CNAPP)
- Sysdig Secure
Threat mappings
MITRE ATLAS
- AML.T0053 AI Agent Tool Invocation
- AML.T0086 Exfiltration via AI Agent Tool Invocation
- AML.T0101 Data Destruction via AI Agent Tool Invocation
- AML.T0105 Escape to Host
- AML.T0122 Exploitation of Remote Services (SSRF and injection hardening keeps an MCP server from being used to reach internal services)
MAESTRO
- Agent Tool Misuse (L7)
- Integration Risks (L7)
- Data Exfiltration (L2)
OWASP LLM Top 10 2026
- LLM01:2026 Prompt Injection (server-side authorization and sink validation limit the consequences of injected tool requests but do not detect the originating prompt injection)
- LLM02:2026 Sensitive Information Disclosure
- LLM03:2026 Excessive Agency
- LLM08:2026 Hidden Context Exposure
- LLM10:2026 Improper Output Handling
OWASP ML Top 10 2023
- N/A
OWASP Top 10 for Agentic Applications 2026
- ASI02:2026 Tool Misuse and Exploitation
- ASI03:2026 Identity and Privilege Abuse
- ASI05:2026 Unexpected Code Execution (RCE)
NIST Adversarial Machine Learning 2025
- NISTAML.039 Compromising connected resources
Cisco Integrated AI Security and Safety Framework
- AISubtech-12.1.1 Parameter Manipulation
- AISubtech-12.1.3 Unsafe System / Browser / File Execution
- AISubtech-14.1.2 Insufficient Access Controls
- AISubtech-14.2.1 Permission Escalation via Delegation
- AISubtech-2.1.2 Capability and Permission Overreach
- AISubtech-4.3.3 Server Rebinding Attack
- AISubtech-8.2.3 Data Exfiltration via Agent Tooling
- AISubtech-9.1.3 Unauthorized or Unsolicited Network Access
- AISubtech-9.1.4 Injection Attacks (e.g., SQL, Command Execution, XSS) (neutralizes model-generated SQL or NoSQL injection arguments at the datastore boundary)
- AITech-12.1 Tool Exploitation
- AITech-12.2 Insecure Output Handling
- AITech-14.1 Unauthorized Access (blocks MCP fetches to internal and cloud-metadata infrastructure)
- AITech-14.2 Abuse of Delegated Authority
- AITech-2.1 Excessive Agency
- AITech-4.3 Protocol Manipulation
- AITech-8.2 Data Exfiltration / Exposure
- AITech-8.3 Information Disclosure
- AITech-9.1 Model or Agentic System Manipulation (neutralizes model-generated SQL or NoSQL injection arguments at the datastore boundary)
Google Secure AI Framework 2.0 - Risks
- IIC: Insecure Integrated Component
- SDD: Sensitive Data Disclosure
- RA: Rogue Actions
Databricks AI Security Framework 3.0
- Agents - Tools MCP Server 13.22: Excessive Permissions and Scope Creep
- Agents - Tools MCP Server 13.23: Data Exfiltration