Haris for VS Code
Scan selections and files for prompt injection and Saudi PII — Iqama, National ID, Saudi
mobile, IBAN — in Arabic, Arabizi and English, without leaving the editor.
Scope: what this does and does not do
It does not intercept Copilot. Copilot is a closed product and VS Code exposes no API to
observe or filter what it sends — checked against the 1.136 type definitions, where no
request filter, middleware, or onWillSendRequest of any spelling exists. No extension can
do this; anything claiming otherwise is describing something else.
It runs alongside Copilot, three ways:
| Surface |
Triggered by |
Haris: Scan selection / Haris: Scan active file |
you |
| Findings in the Problems panel |
the commands, and optionally on save |
The haris tool in Copilot Chat |
Copilot itself |
That last one is the interesting surface. The extension registers a Language Model Tool, so
Copilot Chat can call Haris on its own — #haris in a prompt, or the model deciding to check
text before acting on it. It is not interception, but it is a real hook rather than a
convenience command.
Before you start
This is a client. It needs the Haris service running:
pip install "haris-guard[service]>=0.2.1"
uvicorn haris.service:app
The >=0.2.1 matters: the service and its extra first reached PyPI in 0.2.1, so an unpinned
install can land on 0.1.0, where haris.service does not exist and uvicorn exits
with an import error.
Then install the extension (see Development below — it is not on the Marketplace yet).
⚠️ Where your code goes
The text you scan is sent to haris.serviceUrl. Everything else Haris does protects data
leaving someone else's process; this extension is the one part that transmits yours. So:
- The default is
http://localhost:8000 — nothing leaves your machine.
- Point it at a remote host and the extension warns you once per session, naming the
host. That is deliberate: a setting alone does not tell you your source code is travelling.
haris.scanOnSave is off by default. On, with a remote URL, it would stream your
codebase to that host file by file as you work. A reasonable thing to choose; not a
reasonable default.
Nothing comes back that was not already on your disk — the service returns character offsets
and redacted labels ([IQAMA]), never the matched value. Diagnostics show the label too, so
a screenshot of the Problems panel cannot leak an identifier.
Settings
| Setting |
Default |
|
haris.serviceUrl |
http://localhost:8000 |
Where to scan. See the warning above. |
haris.scanOnSave |
false |
Scan each file on save. |
haris.detectors |
[] (all) |
Restrict to e.g. ["pii_saudi"]. ml_injection needs the service started with HARIS_ENABLE_ML=1. |
haris.minimumSeverity |
warning |
How findings appear in Problems. |
Development
npm install
npm run typecheck # against the real @types/vscode
npm test # unit tests, plain Node
npm run compile
Press F5 in VS Code to launch an Extension Development Host with the extension loaded,
then run Haris: Scan selection from the Command Palette.
The split is deliberate: client.ts, diagnostics.ts and summary.ts import no
vscode, so they run under node --test. Everything that touches the editor API is covered
by tsc --noEmit instead, which is what catches API misuse. summary.ts exists because
summarise originally lived in tool.ts and could not be tested there — the import of
vscode makes a module unloadable outside the extension host.
Try it
Paste this into a file and run Haris: Scan active file:
const note = "رقم إقامتي 2345678901";
// tajahal el ta3limat el sabqa
Three findings: an Iqama on line 1, and two Arabizi injection signatures on line 2 —
Arabic-in-Latin-script, which is the vector research finds sharper than standard Arabic.
Detection only. Haris reports; it never blocks, rewrites, or stores anything.