{"id":"unicode-safety-gate","title":"Adversarial Unicode & Trojan Source gatekeeper","description":"Scans a public GitHub repo, a pull request, a unified diff or a list of files for adversarial Unicode with the 19 rules (USC001-USC019) of dcondrey/unicode-safety-check: bidi controls (Trojan Source), invisible and default-ignorable characters, variation-selector and tag-character payloads (Glassworm), private-use code points, homoglyph and mixed-script identifiers, confusable collisions, misplaced BOM and control characters. Leads with a block/warn/pass verdict, a 0-100 risk score, the top locations (file:line:column) grouped so one trick reads as one finding, and the fix; also returns every finding, a SARIF 2.1.0 log for GitHub code scanning, and model-written exploit explanations that are checked against the findings. Findings and verdict come from deterministic rules; only the explanations use a model. Repo scans read up to 1,000,000 characters, shallowest files first, and list what they skipped.","roi":"A single invisible or reordering character can hide a backdoor from every human reviewer. This gate finds it in a PR or repo before merge and returns the exact line and fix.","audience":"developer","channels":["x402","mcp","rapidapi","apify"],"endpoint":{"method":"POST","url":"https://agents.writerslogic.com/api/v1/unicode-safety-gate","path":"/api/v1/unicode-safety-gate","contentType":"application/json"},"price":{"amount":"0.25","currency":"USDC","network":"base","perCall":true,"failedCallsCharged":false},"inputSchema":{"type":"object","additionalProperties":false,"properties":{"files":{"type":"array","minItems":1,"maxItems":500,"description":"Files to scan in full. Provide exactly one of files, diff, repo or prUrl; total content is capped at 1000000 characters.","items":{"type":"object","additionalProperties":false,"required":["path","content"],"properties":{"path":{"type":"string","minLength":1,"maxLength":500,"description":"Repository-relative path; its extension selects the language and the file risk level."},"content":{"type":"string","maxLength":1000000}}}},"diff":{"type":"string","minLength":1,"maxLength":1000000,"description":"Unified diff (git diff output). Only added lines are scanned; findings carry new-file line numbers."},"repo":{"type":"string","minLength":3,"maxLength":200,"description":"Alternative to files and diff: a public GitHub repository, owner/repo or https://github.com/owner/repo[/tree/ref]. Read from its source archive; files are scanned shallowest first up to the character cap and the rest are listed as skipped."},"ref":{"type":"string","maxLength":200,"description":"Branch, tag or commit for repo; defaults to the default branch."},"prUrl":{"type":"string","minLength":20,"maxLength":300,"description":"Alternative to files and diff: a public GitHub pull request, commit or compare URL. Only added lines are scanned."},"identifierPolicy":{"type":"string","enum":["ascii-only","permitted-scripts"],"description":"Default ascii-only: any non-ASCII identifier is flagged (USC019)."},"permittedScripts":{"type":"array","maxItems":40,"items":{"type":"string","maxLength":40},"description":"Used with permitted-scripts. Default Latin, Common, Inherited."},"scanExcluded":{"type":"boolean","description":"Also scan paths the upstream scanner skips (node_modules/, vendor/, dist/, build/, .lock, .min.js, images, archives). Default false."}}},"resultSchema":{"type":"object","properties":{"verdict":{"type":"string","enum":["block","warn","pass"],"description":"block: a critical finding, or a high finding in a code or config file. warn: other findings. pass: none."},"verdictReason":{"type":"string"},"riskScore":{"type":"integer","description":"0-100: worst severity (critical 90, high 70, medium 40, low 15) plus 1 per further affected line, at most 10."},"status":{"type":"string","enum":["complete","partial"],"description":"partial when files were skipped for size or findings were capped; the result is still signed."},"nextStep":{"type":"string"},"topFindings":{"type":"array","items":{"type":"object","description":"Up to 5 locations, blocking first: rank, path, line, column, severity, blocking, findings (count at that line), ruleIds, codePoints, title, fix."}},"source":{"type":"object","description":"Where the input came from: kind (files, diff, repo, pr), and for repo the owner/repo, ref and commit scanned."},"mode":{"type":"string","enum":["files","diff"]},"summary":{"type":"object","properties":{"total":{"type":"integer"},"returned":{"type":"integer"},"truncated":{"type":"boolean"},"bySeverity":{"type":"object","properties":{"critical":{"type":"integer"},"high":{"type":"integer"},"medium":{"type":"integer"},"low":{"type":"integer"}}},"byRule":{"type":"object","description":"Count per rule id, all 19 rules present."},"blocking":{"type":"integer"},"filesScanned":{"type":"integer"},"filesSkipped":{"type":"integer"}}},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within this response, F1, F2, ..."},"ruleId":{"type":"string","description":"USC001-USC019"},"ruleName":{"type":"string"},"severity":{"type":"string","enum":["critical","high","medium","low"]},"path":{"type":"string"},"line":{"type":"integer"},"column":{"type":"integer","description":"1-based, in code points."},"codePoints":{"type":"string","description":"Space-separated, e.g. \"U+202E\"."},"snippet":{"type":"string","description":"Surrounding text with invisible, control and lookalike characters shown as \\u{XXXX}."},"message":{"type":"string"},"charInfo":{"type":"string"}}}},"sarif":{"type":"object","description":"SARIF 2.1.0 log; columnKind unicodeCodePoints."},"skipped":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"reason":{"type":"string"}}}},"warnings":{"type":"array","items":{"type":"string"}},"explanations":{"type":"array","description":"Model-written, each verified against the finding it names (id, ruleId and codePoints must match).","items":{"type":"object","additionalProperties":false,"required":["id","ruleId","codePoints","attackVector","impact","remediation"],"properties":{"id":{"type":"string","description":"Finding id exactly as given, e.g. F3."},"ruleId":{"type":"string","description":"The finding's ruleId, copied exactly."},"codePoints":{"type":"string","description":"The finding's codePoints, copied exactly."},"attackVector":{"type":"string","description":"How this specific construct is exploited."},"impact":{"type":"string","description":"What an attacker gains if it is merged."},"remediation":{"type":"string","description":"What the reviewer should do."}}}},"llm":{"type":"string","enum":["ok","unavailable","skipped"]},"deterministic":{"type":"object","description":"Engine, finding count, verdict basis and known limits. Findings and verdict involve no model."}}},"outputSchema":{"type":"object","properties":{"data":{"type":"object","properties":{"verdict":{"type":"string","enum":["block","warn","pass"],"description":"block: a critical finding, or a high finding in a code or config file. warn: other findings. pass: none."},"verdictReason":{"type":"string"},"riskScore":{"type":"integer","description":"0-100: worst severity (critical 90, high 70, medium 40, low 15) plus 1 per further affected line, at most 10."},"status":{"type":"string","enum":["complete","partial"],"description":"partial when files were skipped for size or findings were capped; the result is still signed."},"nextStep":{"type":"string"},"topFindings":{"type":"array","items":{"type":"object","description":"Up to 5 locations, blocking first: rank, path, line, column, severity, blocking, findings (count at that line), ruleIds, codePoints, title, fix."}},"source":{"type":"object","description":"Where the input came from: kind (files, diff, repo, pr), and for repo the owner/repo, ref and commit scanned."},"mode":{"type":"string","enum":["files","diff"]},"summary":{"type":"object","properties":{"total":{"type":"integer"},"returned":{"type":"integer"},"truncated":{"type":"boolean"},"bySeverity":{"type":"object","properties":{"critical":{"type":"integer"},"high":{"type":"integer"},"medium":{"type":"integer"},"low":{"type":"integer"}}},"byRule":{"type":"object","description":"Count per rule id, all 19 rules present."},"blocking":{"type":"integer"},"filesScanned":{"type":"integer"},"filesSkipped":{"type":"integer"}}},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within this response, F1, F2, ..."},"ruleId":{"type":"string","description":"USC001-USC019"},"ruleName":{"type":"string"},"severity":{"type":"string","enum":["critical","high","medium","low"]},"path":{"type":"string"},"line":{"type":"integer"},"column":{"type":"integer","description":"1-based, in code points."},"codePoints":{"type":"string","description":"Space-separated, e.g. \"U+202E\"."},"snippet":{"type":"string","description":"Surrounding text with invisible, control and lookalike characters shown as \\u{XXXX}."},"message":{"type":"string"},"charInfo":{"type":"string"}}}},"sarif":{"type":"object","description":"SARIF 2.1.0 log; columnKind unicodeCodePoints."},"skipped":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"reason":{"type":"string"}}}},"warnings":{"type":"array","items":{"type":"string"}},"explanations":{"type":"array","description":"Model-written, each verified against the finding it names (id, ruleId and codePoints must match).","items":{"type":"object","additionalProperties":false,"required":["id","ruleId","codePoints","attackVector","impact","remediation"],"properties":{"id":{"type":"string","description":"Finding id exactly as given, e.g. F3."},"ruleId":{"type":"string","description":"The finding's ruleId, copied exactly."},"codePoints":{"type":"string","description":"The finding's codePoints, copied exactly."},"attackVector":{"type":"string","description":"How this specific construct is exploited."},"impact":{"type":"string","description":"What an attacker gains if it is merged."},"remediation":{"type":"string","description":"What the reviewer should do."}}}},"llm":{"type":"string","enum":["ok","unavailable","skipped"]},"deterministic":{"type":"object","description":"Engine, finding count, verdict basis and known limits. Findings and verdict involve no model."}}},"_provenance":{"type":"object","description":"C2PA-aligned manifest and W3C VC 2.0 (eddsa-jcs-2022) issued by the hub DID; verify at POST /api/v1/verify-provenance"}},"required":["data","_provenance"]},"example":{"files":[{"path":"src/auth.js","content":"const isAdmin = false;\nif (isAdmin‮ ⁦// check later⁩ ⁦) {\n  grant();\n}\n"}]},"openapiOperation":{"operationId":"unicode_safety_gate","summary":"Adversarial Unicode & Trojan Source gatekeeper","description":"Scans a public GitHub repo, a pull request, a unified diff or a list of files for adversarial Unicode with the 19 rules (USC001-USC019) of dcondrey/unicode-safety-check: bidi controls (Trojan Source), invisible and default-ignorable characters, variation-selector and tag-character payloads (Glassworm), private-use code points, homoglyph and mixed-script identifiers, confusable collisions, misplaced BOM and control characters. Leads with a block/warn/pass verdict, a 0-100 risk score, the top locations (file:line:column) grouped so one trick reads as one finding, and the fix; also returns every finding, a SARIF 2.1.0 log for GitHub code scanning, and model-written exploit explanations that are checked against the findings. Findings and verdict come from deterministic rules; only the explanations use a model. Repo scans read up to 1,000,000 characters, shallowest files first, and list what they skipped.\n\nPrice: 0.25 USDC on Base (x402).","x-x402-price-usdc":"0.25","x-x402-amount":"250000","x-audience":"developer","x-sample-url":"https://agents.writerslogic.com/api/v1/samples/unicode-safety-gate","security":[{"x402":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"files":{"type":"array","minItems":1,"maxItems":500,"description":"Files to scan in full. Provide exactly one of files, diff, repo or prUrl; total content is capped at 1000000 characters.","items":{"type":"object","additionalProperties":false,"required":["path","content"],"properties":{"path":{"type":"string","minLength":1,"maxLength":500,"description":"Repository-relative path; its extension selects the language and the file risk level."},"content":{"type":"string","maxLength":1000000}}}},"diff":{"type":"string","minLength":1,"maxLength":1000000,"description":"Unified diff (git diff output). Only added lines are scanned; findings carry new-file line numbers."},"repo":{"type":"string","minLength":3,"maxLength":200,"description":"Alternative to files and diff: a public GitHub repository, owner/repo or https://github.com/owner/repo[/tree/ref]. Read from its source archive; files are scanned shallowest first up to the character cap and the rest are listed as skipped."},"ref":{"type":"string","maxLength":200,"description":"Branch, tag or commit for repo; defaults to the default branch."},"prUrl":{"type":"string","minLength":20,"maxLength":300,"description":"Alternative to files and diff: a public GitHub pull request, commit or compare URL. Only added lines are scanned."},"identifierPolicy":{"type":"string","enum":["ascii-only","permitted-scripts"],"description":"Default ascii-only: any non-ASCII identifier is flagged (USC019)."},"permittedScripts":{"type":"array","maxItems":40,"items":{"type":"string","maxLength":40},"description":"Used with permitted-scripts. Default Latin, Common, Inherited."},"scanExcluded":{"type":"boolean","description":"Also scan paths the upstream scanner skips (node_modules/, vendor/, dist/, build/, .lock, .min.js, images, archives). Default false."}}},"example":{"files":[{"path":"src/auth.js","content":"const isAdmin = false;\nif (isAdmin‮ ⁦// check later⁩ ⁦) {\n  grant();\n}\n"}]}}}},"responses":{"200":{"description":"Paid result with provenance","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"verdict":{"type":"string","enum":["block","warn","pass"],"description":"block: a critical finding, or a high finding in a code or config file. warn: other findings. pass: none."},"verdictReason":{"type":"string"},"riskScore":{"type":"integer","description":"0-100: worst severity (critical 90, high 70, medium 40, low 15) plus 1 per further affected line, at most 10."},"status":{"type":"string","enum":["complete","partial"],"description":"partial when files were skipped for size or findings were capped; the result is still signed."},"nextStep":{"type":"string"},"topFindings":{"type":"array","items":{"type":"object","description":"Up to 5 locations, blocking first: rank, path, line, column, severity, blocking, findings (count at that line), ruleIds, codePoints, title, fix."}},"source":{"type":"object","description":"Where the input came from: kind (files, diff, repo, pr), and for repo the owner/repo, ref and commit scanned."},"mode":{"type":"string","enum":["files","diff"]},"summary":{"type":"object","properties":{"total":{"type":"integer"},"returned":{"type":"integer"},"truncated":{"type":"boolean"},"bySeverity":{"type":"object","properties":{"critical":{"type":"integer"},"high":{"type":"integer"},"medium":{"type":"integer"},"low":{"type":"integer"}}},"byRule":{"type":"object","description":"Count per rule id, all 19 rules present."},"blocking":{"type":"integer"},"filesScanned":{"type":"integer"},"filesSkipped":{"type":"integer"}}},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within this response, F1, F2, ..."},"ruleId":{"type":"string","description":"USC001-USC019"},"ruleName":{"type":"string"},"severity":{"type":"string","enum":["critical","high","medium","low"]},"path":{"type":"string"},"line":{"type":"integer"},"column":{"type":"integer","description":"1-based, in code points."},"codePoints":{"type":"string","description":"Space-separated, e.g. \"U+202E\"."},"snippet":{"type":"string","description":"Surrounding text with invisible, control and lookalike characters shown as \\u{XXXX}."},"message":{"type":"string"},"charInfo":{"type":"string"}}}},"sarif":{"type":"object","description":"SARIF 2.1.0 log; columnKind unicodeCodePoints."},"skipped":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"reason":{"type":"string"}}}},"warnings":{"type":"array","items":{"type":"string"}},"explanations":{"type":"array","description":"Model-written, each verified against the finding it names (id, ruleId and codePoints must match).","items":{"type":"object","additionalProperties":false,"required":["id","ruleId","codePoints","attackVector","impact","remediation"],"properties":{"id":{"type":"string","description":"Finding id exactly as given, e.g. F3."},"ruleId":{"type":"string","description":"The finding's ruleId, copied exactly."},"codePoints":{"type":"string","description":"The finding's codePoints, copied exactly."},"attackVector":{"type":"string","description":"How this specific construct is exploited."},"impact":{"type":"string","description":"What an attacker gains if it is merged."},"remediation":{"type":"string","description":"What the reviewer should do."}}}},"llm":{"type":"string","enum":["ok","unavailable","skipped"]},"deterministic":{"type":"object","description":"Engine, finding count, verdict basis and known limits. Findings and verdict involve no model."}}},"_provenance":{"type":"object","description":"C2PA-aligned manifest and W3C VC 2.0 (eddsa-jcs-2022) issued by the hub DID; verify at POST /api/v1/verify-provenance"}},"required":["data","_provenance"]}}}},"400":{"description":"Invalid request (no payment consumed)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}},"401":{"description":"Invalid X-API-KEY","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}},"402":{"description":"Payment required or invalid","content":{"application/json":{"schema":{"type":"object","description":"x402 v2 PaymentRequired (also base64 in the PAYMENT-REQUIRED header)","properties":{"x402Version":{"type":"integer"},"error":{"type":"string"},"code":{"type":"string"},"resource":{"type":"object"},"accepts":{"type":"array","items":{"type":"object"}},"extensions":{"type":"object"}}}}}},"502":{"description":"Upstream failure; the payment is released or not settled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}}}},"links":{"docs":"https://writerslogic.com/agents/unicode-safety-gate/","docsJson":"https://writerslogic.com/agents/unicode-safety-gate.json","sample":"https://agents.writerslogic.com/api/v1/samples/unicode-safety-gate","openapi":"https://agents.writerslogic.com/openapi.json","catalog":"https://agents.writerslogic.com/api/v1/catalog","verifyProvenance":"https://agents.writerslogic.com/api/v1/verify-provenance","index":"https://writerslogic.com/agents/index.json"}}