security
What it can reach,
and what it cannot.
Written for the person who has to approve this tool. Every claim below was checked against the source on 2026-09-20. Where something could not be checked, the page says “not yet documented” instead of guessing.
01 · why this matters more than most tools
It sits next to
three credentials.
Be blunt about it, because the rest of the page only makes sense in this light. A compromise of this package would not be an npm incident. It would be a credential compromise for every engineer who installed it.
Your Jira identity
An unscoped Atlassian API token is full impersonation of the person who made it: every project that person can see, not only the one you file into.
Your GitHub identity
Typically the repo scope, across every repository that person can reach. solve uses it to push one branch and open one draft pull request.
Your model spend
Spend on your account, and the contents of every prompt the tool builds, which include your source code.
02 · network destinations
Where it connects.
The last row is us, and it is empty.
The tool's own HTTP requests go through one module, and the Anthropic SDK is imported in four files. Those rows are complete, and that is what makes them possible to write. The programs it starts make connections of their own, and those rows say “not yet documented” wherever nobody has traced them host by host. Each row says which host, when, what is sent, and who chose it.
Your Jira site
- Host
- Your credentials go to exactly the URL in
JIRA_BASE_URL, which must be https. Nothing is derived or guessed. They are never sent tojira.baseUrlfrom the config file: that value is used only for the unauthenticated time request below. - When
doctor,plan,ingest,apply,baseline,revertandsolvemake authenticated requests.ingest --dry-rundoes not.status,prsandconfirmmake none, but they read the three Jira variables and refuse to start without them. Before anything authenticated, each of these asks the site for the time with no credentials, so timestamps come from Jira and not from your laptop clock.scanasks the time too when a base URL is configured, and needs no credential.- Sent
- Your Jira email and API token as HTTP basic auth, label searches, and the tickets themselves: rule, path, line, and the matched code after secret redaction, capped at 50 lines and 4 KB.
api.github.com
- Host
- The GitHub REST API. The pull request status reader honours
GITHUB_API_URL. GitHub Enterprise Server has not been exercised: not yet documented. - When
solvetakes a claim on a ref namedrefs/jiraagents/claim/<KEY>before it works, and first asksapi.github.comfor the time with no credentials, so the lease is stamped by the clock of the system the fence lives in.plan,prsandstatusread the state of the pull requests the tool opened.- Sent
- A token from
GH_TOKEN,GITHUB_TOKENorgh auth token, as a bearer header. The time request carries no token.
Your git remote, through git and gh
- Host
- Whatever
originpoints at in the repository you run in. - When
solveonly, and only after all seventeen gates pass. The CLI runsgit pushfor the solver branch andgh pr create --draft. The agent itself cannot push.- Sent
- One branch and one draft pull request, under whatever identity your git and gh are logged in as.
api.anthropic.com
- Host
- The Anthropic API, or the address in
ANTHROPIC_BASE_URLif you set one. Contacted only whenANTHROPIC_API_KEYis in the environment. - When
- The review lenses during
scan, which are ON by default when the key is present. Alsoplan --triage,ingestof a prose report, andsolve. - Sent
- Your source code. A lens reads whole files from the slice it was handed. Turn the lenses off with
scan --no-lenses, or for good withlenses.enabled: []in the config. With no key, none of this runs and the run says so.
semgrep.dev
- Host
https://semgrep.dev/c/p/ci, the public rules registry.- When
initanddoctor --fix, to download the ruleset once and pin its hash. Not duringscan: scans read the cached file and run semgrep with--metrics=off.- Sent
- An anonymous GET. No login, no token, nothing about your repository.
The scanners and package managers it starts
- Host
- Not ours to fix, and not yet documented host by host.
uvxfetches the pinned semgrep from the Python package index on first use.osv-scannerqueries the OSV vulnerability database.trivydownloads its own database.npm auditorpnpm auditasks the npm registry your own npm configuration names. On a machine with Homebrew,install-tools --yesrunsbrew installfor the toolsdoctorreported missing, which reaches Homebrew and wherever its formulae download from, and it warms theuvxcache with the pinned semgrep. Without--yesit prints every command and runs none. Where there is no Homebrew it prints the install commands for you to run yourself, and never pipes a downloaded script into a shell. - When
scan, for semgrep and osv-scanner. trivy runs only with--deep. The audit call runs only when there are dependency findings, to look up an upgrade path, andscanners.remediation.enabled: falseturns it off.install-toolsruns only when you type it.- Sent
- Whatever each of those tools sends. For a vulnerability lookup that is package names and versions from your lockfile.
Strix: your target, its model provider, a container registry
- Host
- Three kinds, and the tool fixes none of them. The URL in
scanners.strix.app_url, which Strix attacks. The model provider Strix is configured for, through its ownSTRIX_LLMandLLM_API_KEYvariables, which jiraagents neither reads nor sets, and does not load from your.env. And the registry Strix pulls its sandbox image from on first use, several gigabytes. Which hosts those last two are is not yet documented. - When
scan --deep, and only withscanners.strix.enabled: true, which is off by default. It also needs a target URL and a running Docker daemon, and says which is missing instead of skipping quietly.- Sent
- Attack traffic to the URL you named. Strix is an agentic penetration tester, not a static analyser: it sends real exploit attempts, so point it at staging you are authorised to test and never at production. It spends your model budget up to
scanners.strix.max_budget_usd. What Strix sends to its model provider is not yet documented.
127.0.0.1, the dashboard
- Host
- A local HTTP server, bound to
127.0.0.1unless you say otherwise. Its pages load nothing from the internet. - When
jiraagents dashboard.- Sent
- Nothing leaves the machine. Bound to a reachable address it refuses to start without
JIRAAGENTS_SERVER_TOKEN, and it refuses every job that writes, because a shared token cannot say which person made the change.
Any host operated by us
- Host
- None. The command line tool contains no request to this site or to anything else we run.
- When
- Never. Not for licensing, not for updates, not for telemetry, not for crash reports. There is no update check and no analytics library in the package.
- Sent
- Nothing. The licence check verifies an Ed25519 signature on your machine with a public key compiled into the tool. The only place this site appears in the code is as text inside a refusal message.
03 · what runs on your machine
What scan starts,
and what solve may touch.
scan runs no test, no build and no install
scan never runs your test suite, your build, your install or any script your repository defines. It starts three static analysers: semgrep against a pinned local ruleset file, osv-scanner, and with --deep trivy. Each reports on standard output and none is given an output path, so nothing is written into the repository being audited. Test coverage arrives through ingest, from a report you produced yourself, for exactly this reason.
The fourth scanner is not static: Strix attacks a running target
Strix is the one scanner that is dynamic. With scan --deep and scanners.strix.enabled: true, which is off by default, the tool starts strix against the URL in scanners.strix.app_url. Strix runs an agent swarm inside a Docker sandbox, sends exploit attempts to that URL, for an hour or more on a deep run, and spends a model budget you cap with scanners.strix.max_budget_usd. The tool starts it in its own cache directory, not in your repository, and reads the run files from there. A run that stops at the budget is reported as partial coverage, never as a clean result.
Not yet documented: what those programs load from a hostile repository
The analysers, and git, npm and pnpm, are third-party programs started inside your repository's directory, and some of them read configuration files they find there. We have not yet gone through them one by one and written down what each will load from a repository that is hostile rather than merely buggy. Every program the tool starts also inherits the environment it was started in, including any token in it. Until that is documented, do not treat scan as safe to point at a repository you do not trust. Run it in a container or a throwaway machine with no credentials in the environment, as you would before opening that repository in any other developer tool.
The solver has three tools, and none of them is a shell
The agent behind solve can read a file, write a file, and say it is done. It has no command execution and no network access of its own. It works in a disposable git worktree with realpath containment, so a symlink cannot lead it outside. It may not write CI configuration, .github, package.json or .npmrc, except in a small set of fixed diff shapes that are re-derived from git at the gate. It never writes a lockfile: the CLI regenerates that with the real package manager and --ignore-scripts. jiraagents doctor --print-policy solver prints the whole policy.
solve does not run your test suite in this release, and says so
The gate that would compare your tests before and after a change reports unverified, in words, rather than a pass. A solver pull request is a draft for that reason among others. The agent takes no irreversible action; the CLI pushes, after seventeen gates, and never opens a pull request that is ready to merge.
04 · least privilege
By default it is you.
It does not have to be.
Out of the box the tool inherits your own authority in Jira and in GitHub, and every audit log
names you rather than the tool. doctor names the account it authenticated as, in
its jira-identity and gh-auth rows, and adds a caveat to
gh-auth when the token carries the workflow scope. It does not warn
that you are running as a person: that check does not exist yet.
A service account, scoped to one project
Instead of a personal API token, use an Atlassian service account whose permissions stop at the one project you file into. It needs to browse, create, edit, comment on and transition issues there, and nothing at site level: the tool never creates a project, a field, a workflow or a screen.
Atlassian serves scoped tokens through api.atlassian.com/ex/jira/<cloudId> rather than your site URL. We have not exercised that route end to end: not yet documented.
A GitHub App or a machine user
Give it contents: write and pull_requests: write on an allowlist of repositories, and no Actions or workflow permission. The cost: GitHub refuses a push that changes a workflow file from an identity without that permission, so the one fix shape that edits a workflow, pinning an action to a commit SHA, will not push under it.
The claim fence needs contents: write on refs/jiraagents/claim/*. The tool has only ever been run as one personal identity. A fine-grained token and an organisation that enforces SSO have not been tried: not yet documented.
scan, explain and both exports need neither credential. A reviewer can evaluate what the
tool finds with no token on the machine at all.
05 · the package
No install scripts.
Readable JavaScript.
npm install -g @jadex-consulting/jiraagents --ignore-scripts
The package has no preinstall, install, postinstall or prepare script, and a test fails the build if one appears. The flag therefore costs you nothing here, and it protects you from every transitive dependency that does have one.
npm view @jadex-consulting/jiraagents@<version> dist.integrity
Compare the hash with the integrity field your lockfile recorded for the same version. npm audit signatures checks the registry's own signature on what you installed. There is no build provenance attestation yet: npm only attests a build it can link to a public commit, and the source repository is private.
What you installed is readable.
The tarball ships the compiled dist directory only: plain JavaScript as the TypeScript compiler emitted it, not minified, not bundled, comments intact. The licence inside the package today does not yet grant a right to read it for security review, and it should. The licence being drafted adds that right in a section of its own, and this page will cite the section the day it ships. If your review needs it in writing before then, write to dhillonvo@icloud.com. Either way the software is proprietary: nothing here is a right to modify or redistribute it.
06 · what it does with secrets
Tokens are wrapped before they travel
Credentials are held in a type whose string, JSON and inspector forms all print a redaction marker, so one cannot leak through a log line, an error or a template.
Nothing secret enters the audited repo
State lives outside the working tree, under your own state directory. doctor fails hard if a .env file is tracked by git.
The licence token is not a credential to anything of yours
It names your organisation, a plan, a developer count and two dates, and carries no email address. It unlocks two commands in this tool and opens no door in Jira, GitHub or Anthropic.
07 · known limitations, stated rather than buried
The local audit journal is not tamper-evident
It is an append-only file on the machine of the person you would be investigating, and a process that can write a hash chain can rewrite it. The records that resist an adversary are external: Jira's audit log, GitHub's organisation audit log, and the audit property the tool writes on every issue it touches.
The semgrep ruleset pin is trust on first use
The ruleset is served anonymously, unsigned and unversioned. Whoever runs init first establishes the hash, and a hostile ruleset served at that moment would be pinned faithfully. It is pinned anyway, because an unpinned ruleset silently changes what is found.
Multi-operator safety exists for solve and not for apply
solve takes a claim before it works. apply takes none, so two people running apply at the same moment are not fenced from each other. Run apply from one place, such as a single CI job. Nobody has yet raced two real machines for one ticket, so the claim fence itself is unmeasured under contention.
08 · report a vulnerability
Email us.
Do not open a public issue.
Write to dhillonvo@icloud.com with [jiraagents security] in the subject. Include the version (jiraagents --version) and what you observed. If a credential may have been exposed, say so in the first line: rotation comes before analysis.
You will get an acknowledgement within two working days. Please do not send a working exploit for somebody else's product: a finding in an upstream dependency belongs with that project's maintainers.