jiraagents

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.

JIRA_API_TOKEN

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.

gh auth token

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.

ANTHROPIC_API_KEY

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.

you 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 to jira.baseUrl from the config file: that value is used only for the unauthenticated time request below.
When
doctor, plan, ingest, apply, baseline, revert and solve make authenticated requests. ingest --dry-run does not. status, prs and confirm make 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. scan asks 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.
fixed by the tool

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
solve takes a claim on a ref named refs/jiraagents/claim/<KEY> before it works, and first asks api.github.com for the time with no credentials, so the lease is stamped by the clock of the system the fence lives in. plan, prs and status read the state of the pull requests the tool opened.
Sent
A token from GH_TOKEN, GITHUB_TOKEN or gh auth token, as a bearer header. The time request carries no token.
you chose it

Your git remote, through git and gh

Host
Whatever origin points at in the repository you run in.
When
solve only, and only after all seventeen gates pass. The CLI runs git push for the solver branch and gh 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.
only with your key

api.anthropic.com

Host
The Anthropic API, or the address in ANTHROPIC_BASE_URL if you set one. Contacted only when ANTHROPIC_API_KEY is in the environment.
When
The review lenses during scan, which are ON by default when the key is present. Also plan --triage, ingest of a prose report, and solve.
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 with lenses.enabled: [] in the config. With no key, none of this runs and the run says so.
fixed by the tool

semgrep.dev

Host
https://semgrep.dev/c/p/ci, the public rules registry.
When
init and doctor --fix, to download the ruleset once and pin its hash. Not during scan: scans read the cached file and run semgrep with --metrics=off.
Sent
An anonymous GET. No login, no token, nothing about your repository.
chosen by each tool

The scanners and package managers it starts

Host
Not ours to fix, and not yet documented host by host. uvx fetches the pinned semgrep from the Python package index on first use. osv-scanner queries the OSV vulnerability database. trivy downloads its own database. npm audit or pnpm audit asks the npm registry your own npm configuration names. On a machine with Homebrew, install-tools --yes runs brew install for the tools doctor reported missing, which reaches Homebrew and wherever its formulae download from, and it warms the uvx cache with the pinned semgrep. Without --yes it 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, and scanners.remediation.enabled: false turns it off. install-tools runs 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.
you enabled it, you chose the target

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 own STRIX_LLM and LLM_API_KEY variables, 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 with scanners.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.
your machine only

127.0.0.1, the dashboard

Host
A local HTTP server, bound to 127.0.0.1 unless 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.
never

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.

jira

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.

github

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.

1
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.

2
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.

3

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

01

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.

02

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.

03

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.