WASViking Docs
⌘K
Getting Started

CI/CD Mobile Security with GitHub Actions

Assess the Android or iOS package your build produces inside your GitHub Actions pipeline with the WASViking Sentinel. Uploads the artefact over HTTPS, runs the static assessment against OWASP MASVS and MASTG, fails the build on new findings with a baseline diff, and publishes results to the GitHub Security tab.

This integration submits the mobile application package your build produces to the WASViking® Mobile Security Assessment, from inside your GitHub Actions runner, and fails the pipeline when the release carries findings you care about. The package is analysed statically against the OWASP Mobile Application Security Verification Standard (MASVS) and the Mobile Application Security Testing Guide (MASTG). Nothing is installed on a device and nothing is executed.

Unlike the DAST flow, there is no mTLS tunnel and no running app to reach: the artefact is a file. The runner uploads it straight to secure object storage with a single-purpose authorisation, so the bytes never pass through the API, and the assessment runs on the same engine the portal uses.

The setup is short. You need one thing in the portal (an API Key scoped to mobile:scan) and one thing in GitHub Actions (that key as a secret). The same key installs the agent and runs the assessment, so there is no separate agent token to manage.

What this integration does

  • Assesses the .apk, .aab, or .ipa your pipeline builds, on every push or pull request.
  • Fails the build by severity with --fail-on, so a release that regresses is blocked before merge.
  • Compares against the previous assessment of the same application with --baseline new, so a build only fails on findings it introduces, not on pre-existing debt.
  • Emits SARIF 2.1.0, consumed natively by GitHub Code Scanning, plus a full JSON summary.
  • Records who built what: the pipeline stamps the provider, repository, branch, commit, and run so every assessment is traceable to a build.
  • Meters against your monthly CI mobile assessment allowance and lists every run in the portal, tagged as a pipeline submission.

How it works

  1. The runner installs the Sentinel agent using your mobile:scan key.
  2. The agent asks the API to authorise one upload and receives a short-lived, single-purpose authorisation for one object.
  3. The agent uploads the package straight to secure object storage. The bytes do not pass through the API or the CDN.
  4. The API verifies the stored object, confirms it is a real application package, and queues the assessment against your organization.
  5. The engine runs its checks (configuration, transport security, cryptography, local storage, platform interaction, binary hardening, third-party components, embedded credentials, and tracking SDKs) and scores the result.
  6. The agent writes wasviking-mobile.sarif and wasviking-mobile.json, and the workflow uploads the SARIF to GitHub Code Scanning.

Access posture

  • Only the application package you name with --file is uploaded. No source code, no runner environment variables beyond the key you pass, and no files outside the working directory are collected.
  • The upload authorisation is single-purpose and short-lived, and pins the exact object; a tampered authorisation is refused.
  • Submission is HTTPS with an API Key. WASViking authenticates with the Authorization: ApiKey <key> header, not Bearer.
  • Revoke access at any time by revoking the API Key in the portal.

Pre-requisites

Requirement Detail
WASViking module Mobile Security Assessment enabled for your organization, with a CI assessment allowance provisioned. It is an add-on; talk to your account contact or partner if it is not yet enabled.
Portal role Admin or Manager, to issue API Keys.
GitHub repository Permission to create Actions secrets and files under .github/.
Workflow permissions contents: read and security-events: write (for the SARIF upload).
Build artefact A .apk, .aab, .xapk, .apks, or .ipa produced by an earlier step in the job.
Runner GitHub-hosted (ubuntu-latest recommended) or self-hosted Linux x86_64.
Network egress HTTPS to api.wasviking.com, the object storage endpoint it returns, and github.com on 443. No inbound is needed.

Not on GitHub Actions? The same gate runs on any CI system where the wasviking-sentinel binary can execute. See wasviking-sentinel mobile.


Step 1: Create an API Key scoped to mobile:scan (portal)

This one key both downloads the agent and runs the assessment.

Go to Settings → System Settings → API Keys and click + New Key.

Field Value
Label Something identifiable, for example GitHub Actions mobile pipeline. Use one key per repository so you can revoke it without affecting other pipelines.
Scopes Select mobile:scan only (Submit mobile app packages (APK/IPA) for assessment from a CI/CD pipeline). Least privilege: do not add scopes the pipeline does not need.
Expiration 90 days is a sensible default; rotate on that cadence.

Save and copy the key once. You will paste it into GitHub in Step 2 as WASV_MOBILE_API_KEY.

You can review or adjust a key's scopes later with Edit on the key row. Editing scopes keeps the same key value, so the pipeline keeps working without re-issuing the secret.


Step 2: Add the GitHub secret

Never commit a key to the repository. Store it as an encrypted Actions secret.

In GitHub, go to the repository's Settings → Secrets and variables → Actions → Secrets and add:

Name Value
WASV_MOBILE_API_KEY The API Key from Step 1.

Use Secrets (encrypted), never Variables, for the key. For multiple environments (staging, production), prefer Environment secrets with required reviewers and deployment protection rules.


Step 3: Add the workflow

Create .github/workflows/wasviking-mobile.yml. The example builds an Android APK; replace the Build the app step with however your project produces its package, and point --file at the artefact.

name: WASViking Mobile Security

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  contents: read
  security-events: write
  actions: read

jobs:
  mobile-assessment:
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      # Replace with your own build. The result must be an .apk, .aab,
      # .xapk, .apks, or .ipa on disk.
      - name: Build the app
        run: ./gradlew assembleRelease

      - name: Install WASViking Sentinel
        env:
          WASV_MOBILE_API_KEY: ${{ secrets.WASV_MOBILE_API_KEY }}
        run: |
          curl -sSL -H "Authorization: ApiKey $WASV_MOBILE_API_KEY" \
            https://api.wasviking.com/api/v1/sentinel/install.sh | sh

      - name: Run WASViking mobile assessment
        env:
          WASV_API_KEY: ${{ secrets.WASV_MOBILE_API_KEY }}
        run: |
          mkdir -p wasviking-reports
          ./.wasviking/wasviking-sentinel mobile \
            --file app/build/outputs/apk/release/app-release.apk \
            --label "${{ github.repository }}@${{ github.sha }}" \
            --fail-on high \
            --baseline new \
            --out ./wasviking-reports

      - name: Upload SARIF to GitHub code scanning
        if: always() && hashFiles('wasviking-reports/wasviking-mobile.sarif') != ''
        uses: github/codeql-action/upload-sarif@v4
        with:
          sarif_file: wasviking-reports/wasviking-mobile.sarif
          category: wasviking-mobile

      - name: Upload raw reports as artifact
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: wasviking-mobile-reports
          path: wasviking-reports/

The assessment command reads the key from WASV_API_KEY, so you do not have to repeat --api-key on the command line. Code Scanning upload (the SARIF step) requires GitHub Advanced Security on private repositories. If you do not have it, drop that step and rely on the uploaded artifact and the portal instead.


Step 4: Command flags

wasviking-sentinel mobile [flags]
Flag Required Description
--file Yes Path to the application package (.apk, .aab, .xapk, .apks, .ipa).
--api-key Yes API Key with the mobile:scan scope. Prefer the WASV_API_KEY env var so the key never lands in the process argv or CI logs.
--label No A label stored with the assessment, for example the release name or the commit.
--fail-on No Single threshold: critical, high, medium, low, or none. "Or above" logic: --fail-on high fails on high and critical. Default: critical.
--baseline No new (only findings absent from the previous assessment of the same app count) or all (total posture). Default: all.
--out No Output directory for SARIF and JSON. Default: current directory.
--timeout No Total budget for upload plus analysis. Default: 40m.
--api No API base URL. Default: https://api.wasviking.com. Also read from WASV_API.

Two files are produced:

  • wasviking-mobile.sarif: SARIF 2.1.0 (GitHub Code Scanning, GitLab, and others).
  • wasviking-mobile.json: the run summary with severity counts, risk score, and provenance.

Exit codes

Code Meaning
0 Success. Nothing at or above the --fail-on threshold (given the chosen baseline).
1 Findings exceed the threshold. Blocks the merge.
2 Operational error (missing package, invalid arguments, authentication or upload failure).

Fail-on policy

--fail-on sets the lowest severity that fails the build, and everything above it also fails.

Setting Behavior
--fail-on none Never fails. Report only.
--fail-on critical Fails on critical only.
--fail-on high Fails on high and critical. A good default for pull requests.
--fail-on medium Fails on medium and above. Stricter, more friction.

A practical rollout: start at critical to keep early friction low, then tighten to high once your baseline is clean.

Baseline diff

--baseline controls what counts toward the fail-on policy. The baseline is the previous completed assessment of the same application (same platform and package identifier), whether that earlier run came from a pipeline or a manual upload in the portal. The comparison is by finding identity, so a version bump does not reset it.

Mode Behavior
all (default) Every finding counts. Use for release branches and audits, to gate on the total posture.
new Only findings absent from the previous assessment count. Use for day-to-day pull requests, so a build fails on what it introduces, not on debt it inherited.

On the first assessment of an application there is nothing to compare against, so new gates on the full set for that run and establishes the baseline for the next one. The SARIF marks each result as new, existing, or fixed, and lists what a release repaired since the baseline.

Build provenance

The pipeline reads the standard CI environment variables and records the provider, repository, branch, commit, run identifier, and actor with the assessment, with no extra flags. The portal shows this next to the run, and the same context rides in the SARIF document, so a finding on a pull request is traceable to the exact build that produced it. GitHub Actions, GitLab CI, Bitbucket Pipelines, and CircleCI are recognised automatically.

What is and isn't collected

WASViking does not collect your repository source code, runner environment variables beyond the key you pass, runner filesystem contents outside the working directory, or any production data. Only the application package you name is uploaded. Embedded secret values found during analysis are stored redacted, never in the clear. Data is processed in the US region, encrypted in transit (TLS 1.2+) and at rest (AES-256), with retention set by your plan. A DPA and EU data residency are available on request; see the Trust Center for the full compliance mapping (ISO 27001, SOC 2, LGPD, GDPR, OWASP MASVS, OWASP MASTG, NIST SSDF, OWASP DSOMM).

Common problems

Problem Likely cause
HTTP 401 Unauthorized API Key revoked, expired, or missing the mobile:scan scope. WASViking uses Authorization: ApiKey <key>, not Bearer.
HTTP 403 feature_not_in_plan Mobile Security Assessment is not enabled for your organization. It is an add-on; ask your account contact or partner to enable it.
HTTP 402 quota_exhausted Your monthly CI mobile assessment allowance is used up. Wait for the cycle to roll over, or raise the allowance.
HTTP 402 quota_not_provisioned The module is on but no CI assessment allowance is set yet. Provision one in the portal.
HTTP 400 unsupported_extension / unsupported_format The file is not a recognised application package. Point --file at the real .apk/.aab/.ipa, not a wrapper or an HTML download page.
HTTP 413 file_too_large The package is over your organization's upload limit.
HTTP 409 assessment is still running The SARIF was requested before analysis finished. The CLI handles this by waiting; you only see it if you call the endpoint directly.
Assessment finished with status=failed The engine could not analyse the package. The JSON output carries the reason.
install.sh download error Network policy blocking api.wasviking.com or the release bucket.

Where this fits in the platform