Skip to content
upseamdocs
Open the App GitHub

Threat model

Where your data goes, what the App can and cannot do, what an attacker would get if Upseam were compromised, and which attacks the patch gates catch and miss.

On this page

This page puts the facts from the security model, Trust and your data and GitHub App in one place and says what they do not cover. It does not replace an independent audit. Upseam has had no independent security audit, and it has no SOC 2 report.

#Where your data goes

The diagram follows one fix from your repository to the model and back. The text under it says the same in words.

diagram
 Your repository (GitHub)
 +------------------------------------------------+
 | source files, lockfiles, .github/upseam.yml    |
 +------------------------------------------------+
          | read through the App (or the Action, or the CLI)
          v
 +------------------------------------------------+
 | Upseam, step by step                           |
 | - archive in a temporary directory             |
 | - find SDKs, versions and matched places       |
 +------------------------------------------------+
     |                                   |
     | change data + files with matches  | path, line, symbol
     | + your key                        v
     v                          +------------------------+
 +------------------------+     | Upseam database        |
 | Your model vendor      |     | no code, no diffs      |
 | OpenAI, Anthropic or   |     | encrypted: model key,  |
 | an OpenAI-compatible   |     | Slack bot token        |
 | endpoint you name      |     +------------------------+
 +------------------------+
     | answer: whole files
     v
 +------------------------------------------------+
 | Patch gates (deterministic)                    |
 +------------------------------------------------+
     | pass: one commit             | fail: nothing is pushed,
     v                              v the finding goes to Needs you
 branch upseam/* in your repository
Where your data goes, from your repository to the model and back
  • Read. The App downloads a repository archive into a temporary directory for one step and deletes it when the step ends. The scan reads source files of the supported languages under 1 MB, and skips directories such as node_modules, vendor and dist.
  • Sent to the model. The change data (the vendor's changelog entry) and the complete content of the files with high-confidence matches, up to 24,000 characters in all, never a file under .github/. With a stored key, also style hints taken from your .editorconfig and Prettier settings.
  • Stored by Upseam. Installation, settings, surfaces, matches as path, line and symbol, proposals, approvals, and encrypted secrets. Not your code, diffs, the model's answer or pull request and issue bodies. The full table is in Trust and your data.
  • With your own GitHub Actions or your own agent, the model is called on your runner and Upseam never sees your key. See Generate in your GitHub Actions and Bring your own agent.
  • The CLI runs on your machine or in your CI, with no Upseam account and no Upseam server. See The CLI.

#What the App can and cannot do

Permission Access Why
Metadata read Basic access to the installation's repositories.
Contents read & write Read the code and lockfiles; write commits to upseam/* branches; send repository_dispatch when fixes are generated in your Actions.
Pull requests read & write Open and update Upseam's pull requests; read Dependabot and Renovate pull requests.
Issues read & write Keep the dashboard issue up to date and read its checkboxes.
Checks read Read your CI result.
Commit statuses read Read your CI result reported as statuses.
Members (organization) read List the organization's teams for the Routing picker.
  • Not requested: Workflows, Actions, Administration, Secrets. Without the Workflows permission GitHub does not let the App change files in .github/workflows. The App cannot read your repository or organization secrets or change repository settings.
  • Writes go to upseam/* branches. Upseam's code refuses to create or update any other branch and to open a pull request from any other branch. Upseam never pushes to your default branch, and it has no code that merges a pull request.
  • GitHub cannot narrow contents: write. The permission applies to the whole repository: GitHub offers no way to limit it to a path or a branch. The limit to upseam/* is a rule in Upseam's code, not something GitHub enforces. Your own protection is a branch protection rule or ruleset on the default branch, which applies to the App unless you list the App as allowed to bypass it.
  • Installation tokens are created for each use with the permissions the step needs, held in memory only, and expire after at most an hour, as GitHub sets. Upseam drops its cached tokens of an installation when GitHub reports that the installation was deleted or suspended.

#If Upseam is compromised

Assume an attacker who controls Upseam's hosting and its secrets: the GitHub App's private key, the database and the master key for encrypted values.

What the attacker could do:

  • Read your code. With the private key the attacker can create installation tokens and read every repository of every installation, as Contents read allows. The database holds no code, but GitHub does.
  • Write to your repositories. The same tokens carry contents: write, and GitHub does not limit it to upseam/*. An attacker outside Upseam's code is not bound by its branch rule and could push to any branch the protection rules of your repository allow, including a branch your CI runs with secrets. Short token lifetime does not limit this: with the key the attacker creates new tokens.
  • Use stored model keys and Slack bot tokens. They are encrypted with AES-256-GCM, and the master key is a secret of the hosting platform. Anyone who holds both the master key and the database can decrypt them. This is the reason to generate in your own GitHub Actions if the key must never leave your secrets.
  • Open pull requests and issues in your repositories as the App.

What limits it:

  • No Workflows, Actions, Administration or Secrets permission. The attacker cannot edit your workflow files, read your Actions secrets or change repository settings through the App.
  • Branch protection and rulesets on your default branch. Require a review and status checks and do not let the App bypass them. Then a push to the default branch fails.
  • Review. Upseam never merges. Nothing reaches the default branch without a person or a rule of yours.
  • ask mode and the patch gates limit what Upseam's own pipeline does. They are code in Upseam's service, so an attacker who controls the service does not have to pass them. Do not count them as a defense against this case.
  • Your CI. A branch the attacker pushes can trigger your push and pull_request workflows with your secrets, because it is a branch of the same repository. Keep secrets away from jobs that run on upseam/* before review, for example with a condition on github.head_ref or an environment with a required reviewer. This is the strongest defense on your side.
  • Uninstall removes the App's access at once. If you suspect a compromise, uninstall, revoke the model key with your vendor and rotate Slack access. See Uninstall.

#Attacks, and what the gates catch and miss

The patch gates are deterministic code that checks the model's answer before anything is pushed. They look at the answer, not at who asked for it.

Attack What stops it What does not
Prompt injection in a vendor changelog. Text that tells the model to add a network call or read environment variables. The brief quotes the changelog as untrusted data and tells the model to ignore instructions in it. The gates refuse new imports, URLs and hosts, forbidden names such as process and fetch, new locals, new control flow and edits outside the matched statement. ask pushes nothing before a person approves. The instruction to the model is not a hard barrier. A patch that passes the gates can still change how data flows within two lines of the matched code, for example by renaming to a name from the vendor's data.
Prompt injection in your repository text. A comment or string in a file that is sent to the model. Same brief rule and the same gates: they check the answer whatever the source of the instruction. Same as above. The gates do not read a comment for intent.
A poisoned changelog. The vendor's published change, or Upseam's copy of it, says to rename to a wrong or malicious symbol. The gates allow new names only from the file or from the vendor's change, only after . or as a key, and refuse anything that is a global or a forbidden name. Upseam's change data is built from vendor sources into data/, which has a code owner on every change. The App does not wait for that review: it reads OpenAI, Anthropic and Gemini model retirements from the vendor's deprecations page directly and uses them with no person checking them first. The gates check the shape of an edit, not whether the vendor's data is true. If the change data names a wrong replacement, the patch uses it. If you turn Simple fixes on, a simple fix opens without approval, so a wrong replacement model id, from a parser error, a changed page layout or a wrong row on the vendor's page, reaches your CI before review. The replacement must match the model id pattern (letters, digits, ., _, :, / and -, no spaces or quotes), and the gates still check the edit. Keep Simple fixes off, the default, to approve each one. Read the pull request and run your tests.
An invented package. The model adds an import or a dependency that does not exist or is hostile. A patch may not add imports, new files or any name that is not in the file or the change. The model is given source files only, never package.json or a lockfile, so the patch edits no dependency list. Upseam does not check a package against a registry. A Dependabot or Renovate bump that Upseam adapts code to is chosen by the bot, not by Upseam, and always waits for approval.
Upseam itself is compromised. See above: the missing permissions, your branch protection and review. The gates and ask do not protect against it. GitHub's contents: write covers the whole repository.
Session theft. Someone gets a signed-in session of the App. The session is an encrypted, HttpOnly, Secure cookie for at most seven days. An installation is shown only to users GitHub lists for it, and every change is checked against a fresh answer from GitHub. Sign out revokes the GitHub token. When you revoke Upseam's authorization in GitHub, your earlier sessions end. A stolen cookie works until it expires, you sign out or you revoke the authorization. A repeated, identical revocation notice from GitHub does not end a session opened after the first one: in that case an open page keeps showing your login until the session ends, while every change is still checked with GitHub. Slack buttons do not check GitHub access: any full member of the connected workspace can press them.

The gates are an allow-list. Legitimate edits they refuse, such as editing a condition or a line with process.env, go to a person too.

#Models and your data

Upseam has no model of its own and no model keys of its own. It sends your vendor the data described above, and your vendor handles it under the terms of your account. Upseam does not use your code to train models. These are the vendors you can connect and their official pages:

Vendor Training and retention Official page
Anthropic API Inputs and outputs of commercial products are not used for training by default. Inputs and outputs are deleted from the backend within 30 days, with exceptions the page lists. Training, retention
OpenAI API Data sent to the API is not used for training unless you opt in. Abuse monitoring logs are kept for up to 30 days by default. Your data
Azure OpenAI Prompts and completions are not used to train foundation models without your permission. Abuse monitoring may store flagged samples. Data, privacy, and security
OpenRouter OpenRouter does not use inputs or outputs for training, but some model providers behind it may. Privacy policy
Your own server Set by you.

The vendors change these terms. Read the page before you connect a key, and check the plan your key belongs to: consumer plans can differ from API terms.

#Secrets and .env files

What the code does, and no more:

  • Which files are read. The scan opens files with the extensions of its supported languages, and manifests and lockfiles to read SDK versions. It also opens .env, YAML, JSON and TOML files, but only to find a retired model id: from such a file it keeps the path, the line and the id, and nothing else of the line is stored, shown, logged or sent to a model. A .env file is never part of a model brief; a model id in one is replaced by the simple fix without a model.
  • Which files reach the model. Only files with a high-confidence match of a vendor change, with a limit of 24,000 characters in all. Files under .github/ are never included.
  • Likely secrets are masked first. Before those files go to your model vendor, Upseam replaces keys in a known format and random-looking strings assigned to secret-like names with placeholders, puts the values back after the answer, and refuses a patch that changes a line holding one. Masking matches patterns and misses some secrets, such as short passwords or keys built at run time; the list is in Secrets in your files. Keep secrets out of source files, and use ignore.paths to keep a path out of the scan.
  • New secrets are refused. A patch that adds a likely secret that was not already in that file is refused. The reason names the file, line and kind, never the value.
  • Your model key is encrypted in the database or stays in your GitHub secrets, and is never logged. See Where keys live.

#Report a vulnerability

Write privately to contact@upseam.dev. Do not open a public issue. Say what is affected (the CLI, the GitHub Action, the GitHub App or the website), the steps to reproduce and the impact you expect. We reply by email.

#What this page is not

It is not an audit. No third party has reviewed Upseam's code or service, and Upseam has no SOC 2 report. The page lists what the code does today; the code is the source of truth, and it changes. Check the changelog and the code when it matters to you.