Code and supply chain security logo

Adversarial Unicode & Trojan Source gatekeeper

$0.25 USDC per call · Developer and security · POST /api/v1/unicode-safety-gate · Id unicode-safety-gate

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.

What you get

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.

Call it

Send the JSON body below to https://agents.writerslogic.com/api/v1/unicode-safety-gate. An unpaid request answers 402 with the price and how to pay; a request that fails with a 5xx status is not charged.

curl -i -X POST https://agents.writerslogic.com/api/v1/unicode-safety-gate \
  -H 'content-type: application/json' \
  -d '{"files":[{"path":"src/auth.js","content":"const isAdmin = false;\nif (isAdmin‮ ⁦// check later⁩ ⁦) {\n  grant();\n}\n"}]}'

Input

FieldTypeRequiredDescription
filesarray<object>; max 500 itemsnoFiles to scan in full. Provide exactly one of files, diff, repo or prUrl; total content is capped at 1000000 characters.
diffstring; length 1..1000000noUnified diff (git diff output). Only added lines are scanned; findings carry new-file line numbers.
repostring; length 3..200noAlternative 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.
refstring; length 0..200noBranch, tag or commit for repo; defaults to the default branch.
prUrlstring; length 20..300noAlternative to files and diff: a public GitHub pull request, commit or compare URL. Only added lines are scanned.
identifierPolicystring; one of "ascii-only", "permitted-scripts"noDefault ascii-only: any non-ASCII identifier is flagged (USC019).
permittedScriptsarray<string; length 0..40>; max 40 itemsnoUsed with permitted-scripts. Default Latin, Common, Inherited.
scanExcludedbooleannoAlso scan paths the upstream scanner skips (node_modules/, vendor/, dist/, build/, .lock, .min.js, images, archives). Default false.

Example request body

{
  "files": [
    {
      "path": "src/auth.js",
      "content": "const isAdmin = false;\nif (isAdmin‮ ⁦// check later⁩ ⁦) {\n  grant();\n}\n"
    }
  ]
}

Result

The response is { "data": ..., "_provenance": ... }. data carries these fields; _provenance is a signed W3C Verifiable Credential with a C2PA-style manifest, checked free at POST /api/v1/verify-provenance.

FieldTypeRequiredDescription
verdictstring; one of "block", "warn", "pass"noblock: a critical finding, or a high finding in a code or config file. warn: other findings. pass: none.
verdictReasonstringno
riskScoreintegerno0-100: worst severity (critical 90, high 70, medium 40, low 15) plus 1 per further affected line, at most 10.
statusstring; one of "complete", "partial"nopartial when files were skipped for size or findings were capped; the result is still signed.
nextStepstringno
topFindingsarray<object>no
sourceobjectnoWhere the input came from: kind (files, diff, repo, pr), and for repo the owner/repo, ref and commit scanned.
modestring; one of "files", "diff"no
summaryobjectno
findingsarray<object>no
sarifobjectnoSARIF 2.1.0 log; columnKind unicodeCodePoints.
skippedarray<object>no
warningsarray<string>no
explanationsarray<object>noModel-written, each verified against the finding it names (id, ruleId and codePoints must match).
llmstring; one of "ok", "unavailable", "skipped"no
deterministicobjectnoEngine, finding count, verdict basis and known limits. Findings and verdict involve no model.

Pay and connect

Available through: x402 (USDC on Base), MCP, RapidAPI, Apify.

Machine-readable