JobyBotsAI Job Hunter

Trust & safety

The 11 rules the bot can't break.

Every guardrail is enforced in code, not in a policy doc. Open the repo and grep — you'll find the exact line that stops the bot from misbehaving.

  1. 1

    Never sends without your one-click approval

    By default (DRAFT_MODE=true), every drafted email lands in a local review queue. The bot does not send a single byte to Gmail until you click 'Send' in the Review Queue UI at localhost:7868.

    Why it matters: Eliminates 'the bot sent something I didn't approve' incidents. You are always the operator of every outbound message from your inbox.

    Enforced in: core/email_sender.py · send_application() · DRAFT_MODE check

  2. 2

    Never sends to an unverified address

    Every recipient candidate goes through MX-record DNS validation. Addresses that don't resolve to a real mail server are dropped before they can reach SMTP.

    Why it matters: Protects your sender reputation. One bounced email is fine; ten in a row gets you flagged as a spammer.

    Enforced in: core/email_validator.py · validate_email()

  3. 3

    Never sends to an address that previously bounced

    Every bounce gets written to the invalid_emails table. The next time the bot considers that address — even months later — it skips silently.

    Why it matters: Repeated sends to known-bad addresses are the #1 signal Gmail uses to quarantine your account.

    Enforced in: core/db.py · mark_invalid_email() / is_invalid_email()

  4. 4

    Never exceeds the safe daily cap

    DAILY_EMAIL_CAP defaults to 50. The bot tracks every send in SQLite and stops the moment the day's count hits the cap, even mid-cycle.

    Why it matters: Cold outreach over ~50/day flips Google's anti-spam classifier. Hard cap means you can't accidentally torch your domain.

    Enforced in: core/email_sender.py · emails_sent_today() check

  5. 5

    Never sends from a non-Gmail address

    The SMTP client is hardcoded to smtp.gmail.com:587 with STARTTLS. There is no configuration for an arbitrary SMTP server, so the bot cannot be repurposed as a generic spam relay.

    Why it matters: If someone steals your installer, they can't aim it at any other provider. It only knows Gmail.

    Enforced in: core/email_sender.py · send_email() · smtplib.SMTP() call

  6. 6

    Never opens an outbound connection you didn't approve

    The bot's only outbound destinations are: Gmail SMTP, the job boards listed on /terms, jobybots.com (one license check per cycle), and the AI APIs you explicitly enable via API key.

    Why it matters: No telemetry, no analytics, no 'phone home' for usage tracking. Inspect outbound traffic with Wireshark; you'll see only those five domains.

    Enforced in: core/net_safety.py · allowed-host list

  7. 7

    Never accesses files outside its own folder

    The bot reads only what's inside the JobyBots folder: resume.pdf, .env, data/jobybot.db, data/*.html. It does not have admin/UAC/sudo permissions and cannot scan your disk.

    Why it matters: Even if the bot were compromised, the blast radius is one folder. It cannot reach your Documents, browser cookies, SSH keys, or anything sensitive.

    Enforced in: All file I/O uses relative paths starting with ./ or ./data/

  8. 8

    Never accepts remote commands

    The Review Queue HTTP server binds to 127.0.0.1 only — never 0.0.0.0. A CSRF token cookie + matching header is required on every POST. The CSP header blocks third-party scripts from making requests against it.

    Why it matters: Nothing on your home Wi-Fi, your office network, or the public internet can reach the queue API. Only YOUR browser, with the page YOU opened, can send actions.

    Enforced in: core/queue_server.py · ThreadingHTTPServer(("127.0.0.1", …)) + _csrf_ok()

  9. 9

    Never runs on a machine that isn't yours

    On first cycle the bot binds itself to your machine's SHA-256 fingerprint via /api/license/bind. Subsequent cycles from a different machine for the same license are rejected with a clear error message.

    Why it matters: Stops the 'I'll share the ZIP with friends' problem. Each paid license = one machine. Move to a new laptop anytime from /portal.

    Enforced in: core/license_check.py · verify_or_bind()

  10. 10

    Never auto-updates itself

    There is no auto-updater. To upgrade you run UPDATE.bat which performs a 'git pull' — and you can read the diff first.

    Why it matters: Auto-updaters are the most common supply-chain attack vector. You decide when (and whether) to take new code.

    Enforced in: Look — there's no updater script at all. Promise.

  11. 11

    Never auto-applies on LinkedIn without explicit opt-in

    Easy Apply automation is OFF by default. Even when ENABLE_EASY_APPLY=true, the bot is in DRY-RUN mode (fills form, screenshots it, stops at Submit). 10/day hard cap. Random 20-60s jitter. Visible browser. Never auto-clicks Follow.

    Why it matters: Easy Apply violates LinkedIn ToS §8.2. We refuse to make that a silent default. You opt in twice (enable + un-dry-run) before any application is submitted, and you watch every click in a real Chromium window. See /easy-apply for the full risk surface.

    Enforced in: core/easy_apply.py · run_easy_apply() · enable_easy_apply + dry_run gates

What the bot will never do

Things you might worry about that simply aren't in the code:

  • Never uploads your résumé to our servers (it stays in your folder)
  • Never uploads your .env, Gmail App Password, or any API key
  • Never reads emails in your inbox (it only sends; bounce-scan reads bounce metadata only)
  • Never imports your contacts, LinkedIn connections, or browser bookmarks
  • Never connects to social media beyond reading public job listings
  • Never sells, shares, or aggregates your data — there is no JobyBots server with your data on it
  • Never modifies system settings, scheduled tasks (except its own), or other applications
  • Never bundles ads, trackers, analytics SDKs, or third-party JavaScript

If you spot a boundary we missed

Responsible-disclosure friendly. Email security@jobybots.com with reproduction steps. Confirmed reports get acknowledged in CHANGELOG and a thank-you in the next release notes.