JoBot is a local-first, single-user desktop/CLI application. This document covers supported versions, how to report vulnerabilities, known accepted residual risks, and the secure-configuration and supply-chain expectations for the project.
JoBot is on the 0.2.x pre-release line. Security fixes land on main
first and are backported to the Active line. There are no backport
branches for older lines (anything before 0.2.x is unsupported).
| Version | Status | Notes |
|---|---|---|
0.2.x |
Active | Current development line. Fixes land on main and ship in the next 0.2.y patch release. |
main branch |
Trunk-of-truth | All fixes are committed here first; tagged releases are cut from main. |
0.1.x |
Unsupported | Pre-history; no fixes. Upgrade to 0.2.x immediately. |
Development milestone tags (release-1.0-alpha, release-1.0, release-2.0) |
Best effort | Internal development milestones, not distributed releases; upgrade to main instead. |
| Any PyPI/npm release claiming a stable version | No such release exists at the time of writing; treat one as unofficial. | — |
Do not open a public GitHub issue, discussion, or pull request for a suspected vulnerability, and do not publicly disclose it before a fix ships.
Report privately through GitHub's private vulnerability reporting:
- Go to https://github.com/aryansinghnagar/JoBot/security/advisories/new
- Submit a description, reproduction steps, and impact assessment
Please include, where applicable:
- Steps to reproduce (commands, configuration, sample inputs)
- Affected component (CLI,
jobot sidecar, GUI shell, adapter, vault/keyring handling, plugin system, CI) - JoBot revision (
jobot --versionoutput or git commit hash) - Whether any secret material was reachable
What to expect:
- Acknowledgement target: within 72 hours of the report (this is a target maintained by a single maintainer, not a contractual SLA).
- Triage target: initial assessment and severity rating within 7 days.
- Fix process: fixes land on
main; coordinated disclosure and a GitHub security advisory are published once a fix is available. - Public CVE/request where appropriate for externally introduced dependencies.
Please report third-party dependency advisories you believe are exploitable
through JoBot; for advisories that are already tracked (see residuals below
and MASTER_PLAN_EXPANDED.md Section 2.2), a report is only needed if you
have an exploit path that is not already documented.
The project tracks its full vulnerability set in MASTER_PLAN_EXPANDED.md
Section 2.2 and risk register R17 (Section 7). The following residuals are
explicitly accepted and documented rather than fixed:
- Advisory: RUSTSEC-2024-0429 / GHSA-wrw7-89jp-8q8g (glib function interception issue).
- Path: the desktop GUI shell in
gui/src-tauriis built on Tauri 2, which transitively depends on the vulnerableglibcrate. There is no in-tree fix available while staying on Tauri 2. - Scope: affects Rust/GTK builds of the desktop shell (Linux GTK-linked builds primarily). The Python core, CLI, and sidecar do not link glib through this path.
- Decision: accepted as a documented residual — decision D3 in
MASTER_PLAN_EXPANDED.mdSection 5 (decided 2026-08-16). - Revisit trigger: migration to Tauri >= 3 / gtk4 (D3 escalation), plus cargo Dependabot/audit monitoring (R17 mitigation).
- User guidance: users who do not build or run the Tauri desktop shell
(
npm run tauri:dev/npm run tauri:build) are not exposed to this dependency; the CLI and sidecar surfaces do not require it.
- Live-browser automation for site adapters (LinkedIn, Naukri, Workday, and
others) is disabled by default and only enabled when the environment
variable
JOBOT_RUN_LIVE_BROWSER=1is set. With the flag unset, adapters return honest "live browser disabled" no-op results and never fabricate a submission (seesrc/jobot/adapters/linkedin.py,src/jobot/adapters/naukri/adapter.py,src/jobot/adapters/workday.py). - Defeating platform anti-bot controls (CAPTCHA solving at scale, bot
detection evasion, bulk high-volume apply) is an explicit non-goal of
this project (
MASTER_PLAN_EXPANDED.mdSection 2.4, Non-goals v1). The project takes a conservative Terms-of-Service stance toward LinkedIn and job boards; risky-feature ideas requireJOBOT_ENABLE_RISKY=1plus per-feature flags (decision D12) and hard caps remain even when enabled (D24). - Residual accepted: users who enable live-browser mode do so at their own risk with respect to platform ToS; the software provides rate caps and human-approval defaults (D15: submission autonomy is human-by-default) but does not promise account safety on third-party platforms.
Additional tracked-but-unresolved items (vite/esbuild/nanoid advisory set,
CodeQL py/incomplete-url-substring-sanitization alerts) are enumerated in
MASTER_PLAN_EXPANDED.md Section 2.2 with remediation workstreams in WS1;
they are handled as normal security work, not permanent acceptances.
Secrets handling in JoBot is layered; keep it that way:
- API keys and credentials belong in the OS keyring, never in files.
jobot config set <key> <value>routes secret values into the OS keyring (servicejobot, seesrc/jobot/secrets.py);jobot config show/getmask them..envholds non-secret runtime configuration only. - Credential vault:
src/jobot/storage/vault.py(CredentialVault) encrypts profiles with Fernet (AES-256). The master key is stored in the OS keyring (servicejobot_vault). If the keyring is unavailable, the master key falls back to a keyfile at~/.jobot/vault/master.key, which JoBot restricts to0600on POSIX systems.- If you run on the keyfile fallback, verify with
ls -lthat~/.jobot/vault/master.key(and~/.jobot/profiles/*.enc) are readable only by your user; on Windows, restrict the%USERPROFILE%\.jobotdirectory to your account. - Never copy, commit, or back up the vault master key alongside encrypted data; never share a machine account running JoBot with untrusted users.
- If you run on the keyfile fallback, verify with
- Logging: JoBot masks secret values in CLI output (
mask()keeps at most a 4-character prefix). Do not paste raw secrets into bug reports, logs, or screenshots — redact before attaching (see the bug report template). - Human approval is the default for real submissions (decision D15);
auto-submit modes exist but are opt-in and capped by the policy engine.
Prefer
--dry-runwhile evaluating the system.
Job descriptions, search results, scraped page content, and any text sourced from third-party sites are untrusted content. They are passed through LLM-powered tailoring, matching, and question-answering steps.
- Active Prompt Guard (
src/jobot/security/prompt_guard.py): All external text (job titles, descriptions, candidate questions) passes through regular expression sanitizers that neutralize instruction overrides, role-switch attempts (e.g.,you are now a...,act as a...), prompt exfiltration queries, and delimiter tags before entering LLM prompts. - Candidate Grounding Gate (
CandidateGroundingVerifier): LLM output is strictly validated against the candidate's truth ledger before inclusion in resumes or cover letters. Unverified skills, employers, or dates cause immediate rejection. - Candidate Data Flow & PII Disclosure:
- During resume tailoring and cover letter generation, candidate name, contact info, experience descriptions, education, and skills are sent to the configured LLM provider.
- API keys are injected server-side by HTTP provider classes and never embedded in prompt bodies.
- Users can choose local inference (via Ollama) if zero cloud PII transmission is required.
- Human Review Before Submission: Users should review generated materials and form fields in the Approval Inbox before authorizing submission. If an adversarial job description bypasses sanitization, human verification ensures no unauthorized claims are submitted.
- CI actions: GitHub Actions used in
.github/workflows/must be pinned to the most restrictive ref that is practical; when adding or updating a workflow step, pin third-party actions to a full commit SHA (this is the target policy — the existing workflows currently pin to major-version tags, and the migration is tracked as WS1 W4 inMASTER_PLAN_EXPANDED.md). Workflowpermissionsblocks are required and set to least privilege (e.g.contents: read). - Dependency updates: Dependabot is enabled for the repository; CodeQL scanning runs via GitHub default code-scanning setup (no custom workflow file — see repository Settings → Code security). Known advisories are triaged against the set documented in Section 2.2 of the expanded master plan.
- Plugins are deny-by-default. The plugin system
(
src/jobot/plugins/) validates a manifest against fixed allowlists: only declared permission categories inALLOWED_PERMISSIONS, only allowlisted packages inALLOWED_REQUIRES, and entrypoints may never live in forbidden internal modules (jobot.storage.vault,jobot.secrets,jobot.config). Installation runs a static audit (permissions, dependencies, entrypoints, secret-pattern scan) with no execution of plugin code; anything outside the allowlists is rejected. - No telemetry by default. The application is local-first; no crash reporting or analytics leave the machine unless explicitly enabled.
- Secrets never enter the repository. History has been verified with
gitleaks; keep it that way — see
CONTRIBUTING.mdfor the "no secrets in diff" checklist item on every pull request.
The core Python system is licensed AGPL-3.0-only and site adapters are MIT
(see LICENSE and README.md). This policy covers the entire repository,
including the Tauri desktop shell in gui/ and the JSON-RPC sidecar.