Skip to content

Harden gateway security: secrets, authz, and input validation - #2183

Closed
quantova-inc wants to merge 1 commit into
Qiskit:mainfrom
quantova-inc:security/harden-gateway-vulnerabilities
Closed

Harden gateway security: secrets, authz, and input validation#2183
quantova-inc wants to merge 1 commit into
Qiskit:mainfrom
quantova-inc:security/harden-gateway-vulnerabilities

Conversation

@quantova-inc

Copy link
Copy Markdown

Summary

This PR addresses a set of security issues found while auditing the gateway, client, and deployment configuration. Each change is defensive and aims to fail closed.

Configuration / secrets

  • Fail closed on missing secret key: the app now refuses to boot when DJANGO_SECRET_KEY is unset and DEBUG is off, instead of silently using a public hardcoded key. A hardcoded fallback remains only for DEBUG/tests.
  • Secure defaults: DEBUG now defaults to 0; ALLOWED_HOSTS defaults to localhost (not *) in production.
  • Auth fail-closed: an unknown SETTINGS_AUTH_MECHANISM now raises instead of silently falling back to the mock_token backend.
  • Token encryption: the Fernet key is derived with SHA-256 (full entropy) instead of space-padding the secret; added an optional dedicated TOKENS_ENCRYPTION_KEY. decrypt_env_vars now drops a value it cannot decrypt rather than injecting ciphertext into the runtime environment.

Authorization / data exposure

  • get_jobs: provider listings no longer serialize other authors' private result field.
  • Base serializers: the base Job/Program serializers now use explicit field allowlists so env_vars / account_id / instance_crn are never serialized implicitly.

Input validation

  • Container image: validate the image reference grammar and enforce a registry path boundary so a configured registry is not matched by registry.attacker.com/....
  • Entrypoint: validate it is a relative .py path with no .. segments or shell characters before it is interpolated into the runner command.
  • Artifact tar → COS: reject absolute / .. traversal members when uploading the artifact, and drop the duplicate plaintext ENV_JOB_ARGUMENTS literal env var (arguments are delivered via COS at ARGUMENTS_PATH).

Templates / deployment

  • Move the extra template directory off world-writable /tmp/templates to /etc/gateway/templates (env-overridable via GATEWAY_TEMPLATES_DIR) and update the Helm chart mount.
  • docker-compose.yaml now provides a local dev secret key and ALLOWED_HOSTS so the new fail-closed boot still works locally.

Client

  • Basename the download target so a crafted file name cannot escape the download directory.
  • Type-validate the result-decoder payload before constructing objects.

Testing

  • py_compile passes on all changed Python files.
  • Standalone unit checks of the new pure logic (image grammar + registry boundary, entrypoint rules, tar member normalization, Fernet round-trip) pass.
  • The full tox -e py311 suite was not run in my local environment (Python 3.11 + Ray/Qiskit not available); CI should exercise it.

Notes

  • Token env vars are still passed to Code Engine fleets as literal env vars; migrating them to secret_key_ref is left as a follow-up as it touches the fleet-submission flow more broadly.

Address a set of security issues found during an audit of the gateway,
client, and deployment config:

- settings: fail closed when DJANGO_SECRET_KEY is unset and DEBUG is off;
  default DEBUG to 0 and require an explicit ALLOWED_HOSTS in production;
  fail closed on an unknown SETTINGS_AUTH_MECHANISM instead of silently
  falling back to the mock_token backend.
- crypto: derive the token-encryption Fernet key with SHA-256 (full
  entropy) instead of space-padding the secret; add an optional dedicated
  TOKENS_ENCRYPTION_KEY; decrypt_env_vars now fails closed (drops a value
  it cannot decrypt rather than injecting ciphertext into the runtime env).
- images: validate the container image reference grammar and enforce a
  registry path boundary so "registry" is not matched by
  "registry.attacker.com/...".
- entrypoint: validate it is a relative .py path with no ".." or shell
  characters before it is interpolated into the runner command.
- jobs: provider get_jobs listings no longer serialize other authors'
  private result field.
- fleets: reject path-traversal members when uploading the artifact tar to
  COS; drop the duplicate plaintext ENV_JOB_ARGUMENTS literal env var
  (arguments are delivered via COS at ARGUMENTS_PATH).
- templates: move the extra template directory off world-writable
  /tmp/templates to /etc/gateway/templates (env-overridable) and update the
  chart mount.
- serializers: give the base Job/Program serializers explicit field
  allowlists so env_vars/account_id/instance_crn are never serialized
  implicitly.
- client: basename the download target so a crafted name cannot escape the
  download directory; type-validate the result decoder payload.
- docker-compose: provide a local dev secret key and ALLOWED_HOSTS so the
  new fail-closed boot still works locally.
@quantova-inc
quantova-inc requested a review from a team as a code owner June 1, 2026 21:19
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@Tansito

Tansito commented Jun 5, 2026

Copy link
Copy Markdown
Member

@quantova-inc thanks for your contribution, do you mind to sign the CLA?

@avilches avilches closed this Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants