NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🐹
🐹 Go
Not in CISA KEV
HIGH severity

CVE-2026-33030 — nginx-ui

HIGH

CVE-2026-33030 is a high-severity (CVSS 8.8) OS Command Injection vulnerability in github.com/0xJacky/nginx-ui. The records list no fixed version yet; check the vendor advisory below and apply the mitigations in the meantime.

Nginx UI: Unencrypted Storage of DNS API Tokens and ACME Private Keys

Also known asGHSA-5hf2-vhj6-gj9mGO-2026-4901
Published
Updated
Affected
1 pkg
Patched
See advisory
Exploits
None indexed
Exploitation data as of Nov 8, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • A successful exploit gives an attacker total control of the affected component, not partial access.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-33030.

EPSS Exploitation Probability

via FIRST.org ↗
0.3%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs21th percentile — riskier than 21% of all scored CVEsHighest risk
0.00%0.29%0.59%0.88%0.0%0.3%May 26Sep 26Nov 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

Where this sits among everything scored

Real-World Exposure

1 pkg affected
🐹github.com/0xJacky/nginx-ui

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.

Description

Summary

Nginx-UI contains an Insecure Direct Object Reference (IDOR) vulnerability that allows any authenticated user to access, modify, and delete resources belonging to other users. The application's base Model struct lacks a user_id field, and all resource endpoints perform queries by ID without verifying user ownership, enabling complete authorization bypass in multi-user environments.

Severity

High - CVSS 3.1 Score: 8.8 (High)

Vector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

Note: Original score was 7.5. The score was updated to 8.8 after discovering that sensitive data (DNS API tokens, ACME private keys) is stored in plaintext, which when combined with IDOR allows immediate credential theft without decryption.

Product

nginx-ui

Affected Versions

All versions up to and including v2.3.3

CWE

CWE-639: Authorization Bypass Through User-Controlled Key

Description

Exposed DNS Provider Credentials

The dns.Config structure (internal/cert/dns/config_env.go) contains API credentials:

type Configuration struct {
    Credentials map[string]string `json:"credentials"`  // API tokens here
    Additional  map[string]string `json:"additional"`
}
ProviderCredential FieldsImpact if Leaked
CloudflareCF_API_TOKENFull DNS zone control
Alibaba Cloud DNSALICLOUD_ACCESS_KEY, ALICLOUD_SECRET_KEYFull DNS control + potential IAM access
Tencent Cloud DNSTENCENTCLOUD_SECRET_ID, TENCENTCLOUD_SECRET_KEYFull DNS control
AWS Route53AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEYRoute53 + potential AWS access
GoDaddyGODADDY_API_KEY, GODADDY_API_SECRETDNS record modification

Combined Attack: IDOR + Plaintext Storage

When the IDOR vulnerability is combined with plaintext storage, attackers can directly extract API tokens from other users' resources:

Attack Chain:
┌─────────────────────────────────────────────────────────────────┐
│ 1. Attacker authenticates with low-privilege account            │
│ 2. Uses IDOR to enumerate: /api/dns_credentials/1,2,3...      │
│ 3. Reads plaintext API tokens directly from HTTP response       │
│ 4. No decryption needed - tokens stored in cleartext            │
│ 5. Uses stolen tokens to:                                       │
│    - Modify DNS records (domain hijacking)                      │
│    - Issue fraudulent SSL certificates                          │
│    - Pivot to cloud infrastructure                              │
└─────────────────────────────────────────────────────────────────┘

PoC: Extracting Plaintext Credentials via IDOR

# Attacker with low-privilege token accessing admin's DNS credential
curl -H "Authorization: $ATTACKER_TOKEN" \
     https://nginx-ui.example.com/api/dns_credentials/1

# Response contains PLAINTEXT API token (no decryption required):
{
    "id": 1,
    "name": "Production Cloudflare",
    "provider": "cloudflare",
    "config": {
        "credentials": {
            "CF_API_TOKEN": "yhyQ7xR...plaintext_token_visible..."
        }
    }
}

Updated CVSS Score with Plaintext Storage

The plaintext storage increases the confidentiality impact:

CVSS 3.1 Score: 8.8 (High)

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

  • Scope Changed (S:C): Impact extends to external services (DNS providers, cloud platforms)
  • High Confidentiality (C:H): Plaintext API tokens immediately usable
  • High Integrity (I:H): DNS records, certificates can be modified
  • High Availability (A:H): Services can be disrupted via DNS/certificate manipulation

Attack Scenario: Certificate Hijacking

1. Attacker creates low-privilege account on nginx-ui
2. Uses IDOR to enumerate all DNS credentials: /api/dns_credentials/1,2,3...
3. Steals Cloudflare API token from admin's credential
4. Uses token to:
   - Modify DNS records
   - Issue fraudulent Let's Encrypt certificates
   - Intercept traffic to victim domains

Credit

Discovered by security researcher during authorized security audit.

Recommendation

Immediate Mitigation

  1. Add User Ownership to Models
// model/model.go
type Model struct {
    ID        uint64          `gorm:"primary_key" json:"id"`
    UserID    uint64          `gorm:"index" json:"user_id"`  // Add this field
    CreatedAt time.Time       `json:"created_at"`
    UpdatedAt time.Time       `json:"updated_at"`
    DeletedAt *gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
}
  1. Filter Queries by Current User
// api/certificate/dns_credential.go
func GetDnsCredential(c *gin.Context) {
    id := cast.ToUint64(c.Param("id"))
    currentUser := c.MustGet("user").(*model.User)

    d := query.DnsCredential
    dnsCredential, err := d.Where(
        d.ID.Eq(id),
        d.UserID.Eq(currentUser.ID),  // Add user filter
    ).First()

    if err != nil {
        cosy.ErrHandler(c, err)
        return
    }
    // ...
}
  1. Add Authorization Middleware
// middleware/authorization.go
func RequireOwnership(resourceType string) gin.HandlerFunc {
    return func(c *gin.Context) {
        currentUser := c.MustGet("user").(*model.User)
        resourceID := cast.ToUint64(c.Param("id"))

        // Check if resource belongs to current user
        ownerID, err := getResourceOwner(resourceType, resourceID)
        if err != nil || ownerID != currentUser.ID {
            c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
                "message": "Access denied",
            })
            return
        }
        c.Next()
    }
}

Database Migration

-- Add user_id column to all resource tables
ALTER TABLE dns_credentials ADD COLUMN user_id BIGINT;
ALTER TABLE certs ADD COLUMN user_id BIGINT;
ALTER TABLE acme_users ADD COLUMN user_id BIGINT;
ALTER TABLE sites ADD COLUMN user_id BIGINT;
ALTER TABLE streams ADD COLUMN user_id BIGINT;
ALTER TABLE configs ADD COLUMN user_id BIGINT;

-- Set default owner for existing resources
UPDATE dns_credentials SET user_id = 1 WHERE user_id IS NULL;
UPDATE certs SET user_id = 1 WHERE user_id IS NULL;

-- Add foreign key constraint
ALTER TABLE dns_credentials ADD CONSTRAINT fk_dns_credentials_user
    FOREIGN KEY (user_id) REFERENCES users(id);

Long-term Improvements

  1. Implement role-based access control (RBAC)
  2. Add audit logging for resource access
  3. Implement resource sharing functionality with explicit permissions
  4. Add integration tests for authorization checks

Remediation for Plaintext Storage

Immediate Fix: Encrypt Sensitive Fields

Apply the same serializer:json[aes] pattern used for S3 credentials to DNS and ACME data:

model/dns_credential.go:

type DnsCredential struct {
    Model
    Name         string      `json:"name"`
    Config       *dns.Config `json:"config,omitempty" gorm:"serializer:json[aes]"` // Add AES encryption
    Provider     string      `json:"provider"`
    ProviderCode string      `json:"provider_code" gorm:"index"`
}

model/acme_user.go:

type AcmeUser struct {
    Model
    // ...
    Key PrivateKey `json:"-" gorm:"serializer:json[aes]"` // Add AES encryption
    // ...
}

Data Migration

Existing plaintext data must be re-saved to trigger encryption:

func MigrateSensitiveData() error {
    // Migrate DNS credentials
    var dnsCreds []model.DnsCredential
    query.DnsCredential.Find(&dnsCreds)
    for _, cred := range dnsCreds {
        query.DnsCredential.Save(&cred) // Re-save triggers AES encryption
    }

    // Migrate ACME users
    var acmeUsers []model.AcmeUser
    query.AcmeUser.Find(&acmeUsers)
    for _, user := range acmeUsers {
        query.AcmeUser.Save(&user)
    }

    return nil
}

Summary of Required Changes

FileLineCurrentFix
model/dns_credential.go7serializer:jsonserializer:json[aes]
model/acme_user.goKey fieldserializer:jsonserializer:json[aes]

References

Disclosure Timeline

  • 2026-03-13: Vulnerability discovered through source code audit
  • 2026-03-13: Vulnerability successfully reproduced in local Docker environment
  • 2026-03-13: All IDOR operations verified: READ, MODIFY, DELETE
  • 2026-03-13: Security advisory prepared
  • [Pending]: Report submitted to nginx-ui maintainers
  • [Pending]: CVE ID requested
  • [Pending]: Patch developed and tested
  • [Pending]: Public disclosure (21-90 days after vendor notification)

Affected Packages

1 total
EcosystemPackageVulnerable rangeFix
🐹Gogithub.com/0xJacky/nginx-uiall versionsNo fix

Affected Products

1 product · 1 configurations
Application
nginx uinginxui
≤ 2.3.3
range

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/0xJacky/nginx-ui, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Remediation status

    The records we use list no patched version of github.com/0xJacky/nginx-ui for CVE-2026-33030. Check the maintainer's advisory, and where your build allows, override or pin the dependency away from the vulnerable range.

  3. Mitigate without a patch

    Stop passing untrusted input into the interpreter or shell: call the affected binary with an argument array rather than a composed command string, reject anything outside a strict allowlist of expected values, and run the component under an account that cannot reach beyond the work it legitimately does.

Frequently Asked Questions

## Summary Nginx-UI contains an Insecure Direct Object Reference (IDOR) vulnerability that allows any authenticated user to access, modify, and delete resources belonging to other users. The application's base `Model` struct lacks a `user_id` field, and all resource endpoints perform queries by ID without verifying user ownership, enabling complete authorization bypass in multi-user environments. ## Severity **High** - CVSS 3.1 Score: **8.8 (High)** Vector String: `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H` **Note**: Original score was 7.5. The score was updated to 8.8 after discoverin
O3 Security · Impact-Aware SCA

Is CVE-2026-33030 in your dependencies?

Find it across Go, including transitive dependencies.

CVE-2026-33030: nginx-ui (High 8.8)