Skip to main content

Security attachment scanning

Multiforum's first-party download scanner is split into two independently deployed parts:

  • security-attachment-scan is a TypeScript plugin that runs in the Multiforum backend and participates in download pipelines;
  • multiforum-plugin-security-scan-service is a Python service that downloads and inspects the untrusted bytes outside the main application process.

The service combines VirusTotal reputation with static ZIP checks for dangerous extensions, path traversal, excessive compression, and optional channel rules such as requiring a root README or LICENSE.

Authentication model​

The plugin sends POST /scan with an X-API-Key header. The two sides must share the same value:

LocationName
Multiforum plugin secretSCAN_SERVICE_API_KEY
Scan service secretSCAN_API_KEY

The VirusTotal key is a separate scan-service secret named SCAN_VIRUSTOTAL_API_KEY. Do not enter it in the Multiforum plugin settings.

The supported Cloud Run configuration allows requests to reach the service and protects /scan with the shared API key. This lets a Multiforum backend hosted outside Google Cloud call the service without a Google identity token. The unauthenticated /health response contains no secret data.

Supported production deployment​

The scan-service repository contains the supported infrastructure-as-code workflow. It uses Terraform for Cloud Run, Artifact Registry, Secret Manager, IAM, probes, and scaling; GitHub Actions authenticates to Google Cloud with Workload Identity Federation and deploys an immutable commit-tagged image.

The deployment then runs mfctl with a narrowly scoped OAuth machine identity to reconcile all of the application-side state:

  • install and enable security-attachment-scan version 0.5.1;
  • save the Cloud Run service URL;
  • copy the shared API key into SCAN_SERVICE_API_KEY without putting it in the manifest or logs;
  • configure the blocking policy;
  • configure the downloadableFile.created, .updated, and .downloaded pipelines.

Follow the scan service's production deployment runbook for bootstrap variables, GitHub environment values, deployment verification, rotation, and rollback. Avoid making lasting changes by hand in Cloud Run; Terraform will treat them as drift.

Manual Multiforum configuration​

If the scan service is already deployed and you are configuring Multiforum in the UI:

  1. Install and enable security-attachment-scan version 0.5.1.
  2. Set SCAN_SERVICE_API_KEY to the same value as the service's SCAN_API_KEY.
  3. Set Service URL to the Cloud Run base URL, without /scan.
  4. Choose blockOn: malicious blocks malicious findings; suspicious also blocks suspicious findings.
  5. Keep onError: block to fail closed unless availability is deliberately more important than an inconclusive security result.
  6. Add the plugin to the desired download pipelines. Enabling the plugin alone does not schedule it.

For a server-wide requirement, include the scanner in all three downloadableFile.* pipelines. A channel cannot bypass a server pipeline. If scanning is optional by channel, omit the server upload requirement and add the scanner to that channel's discussionChannel.created pipeline. A server-wide upload scan takes precedence if both policies select the scanner, so the same bytes are not scanned twice merely because the discussion joins a channel.

Channel plugin settings can additionally require a README or LICENSE at the root of ZIP uploads.

Quarantine behavior​

With the default fail-closed policy, a file remains unavailable until the current file version has a clean result. PENDING, SUSPICIOUS, INFECTED, and FAILED are logical quarantine states; the file and discussion remain in the database, but the download route refuses to serve the bytes.

Replacing a file creates a new version and returns it to quarantine. A clean result or human release for an older version never approves the replacement.

Diagnose failures​

Start with the public diagnostic on the download's Pipelines tab:

CodeMeaning
SCAN_COMPLETEThe scan completed without finding a threat.
SCAN_NOT_APPLICABLEThe event contained no attachment to scan.
SCAN_SUSPICIOUSThe scan needs human review.
SCAN_MALWARE_DETECTEDThe scan detected a threat.
SCAN_PROVIDER_ERRORThe service or one of its providers could not complete.
SCAN_CONFIGURATION_REQUIREDThe service URL or shared plugin secret is missing.

Completed diagnostics include a correlationId. Search for that value in the private Multiforum backend and Cloud Run logs to follow the same request. The public diagnostic intentionally omits signed attachment URLs, credentials, provider bodies, and stack traces.

For SCAN_PROVIDER_ERROR, verify in this order:

  1. the service /health endpoint responds;
  2. the plugin Service URL is the current deployment URL;
  3. SCAN_SERVICE_API_KEY and SCAN_API_KEY match;
  4. Cloud Run logs contain the diagnostic correlation ID;
  5. the service can fetch the private, time-limited attachment URL before it expires;
  6. VirusTotal or another provider is not returning a transient error.

Retry only after correcting a configuration problem or allowing a transient failure to clear. Pipeline retry limits still apply.

See Plugin pipelines for rollout, retry, and review behavior and Declarative plugin configuration for plan/apply automation.