Oct 23, 2026·5 min read·2 visits
Decoupled parameter handling in SiYuan's Bazaar installer allowed package archives to overwrite arbitrary installed plugins without validating package manifest consistency.
An insufficient verification of data authenticity vulnerability in SiYuan prior to version 3.7.4 allows an attacker to overwrite arbitrary installed marketplace packages (plugins, widgets, themes, and templates). By providing a mismatched package name and package archive repository URL during a Bazaar installation request, arbitrary file write into trusted plugin directories can be achieved, enabling persistence and execution across application restarts.
SiYuan is an open-source personal knowledge management system that supports extensible plugins, widgets, themes, and templates via its built-in marketplace called Bazaar. The system processes installation and update requests for these packages through dedicated kernel endpoints.
In versions of SiYuan prior to 3.7.4, the package installer component suffered from a decoupled parameter verification defect cataloged under CWE-345 (Insufficient Verification of Data Authenticity). When installing or updating a package, the application accepted parameters such as packageName, repoURL, repoHash, and pkgType directly from the client request without enforcing structural consistency between the requested packageName and the internal manifest contained within the downloaded archive.
This flaw exposed an attack surface where an attacker with network access to the API interface or ability to issue requests in a same-origin context could specify a target package name corresponding to a legitimate, highly trusted plugin while directing repoURL to a custom repository containing arbitrary code. Upon extraction, the server overwrote existing files within the target package directory.
The underlying flaw resides within kernel/bazaar/install.go inside the installPackage function. The application logic derived the destination path (installPath) on the local filesystem directly from the client-supplied packageName parameter.
The installation workflow executed three primary stages without proper validation bounds:
packageName and compute installPath relative to the workspace directory.repoURL and extract its contents into a temporary directory.installPath, overwriting existing files if present.Because the installer did not parse or validate the inner manifest file (e.g., plugin.json or theme.json) located inside the downloaded ZIP archive prior to copying, the internal package identity was never compared against packageName. Furthermore, during fresh installations (update = false), the system failed to verify whether installPath was empty before performing file extraction and copy operations.
Patch commit 26ccb40d390eb7d9b04673629a58ab1d69cc7e53 introduced two fundamental validation routines into installPackage in kernel/bazaar/install.go to enforce parameter alignment and prevent directory collision.
First, when update is false, the application checks installPath using os.ReadDir. If the directory exists and contains entries, the installation terminates immediately with marketplace package install path already exists.
Second, after unzipping the archive into a temporary folder, installPackage identifies the mandatory manifest file corresponding to pkgType (e.g., plugin.json). It parses the manifest with ParsePackageJSON and asserts that pkg.Name inside the file equals the request parameter packageName. If a mismatch occurs, execution halts with marketplace package name mismatch.
func installPackage(data []byte, installPath, pkgType, packageName string, update bool) (err error) {
// Reject overwriting an existing non-empty directory when update is false
if !update {
entries, statErr := os.ReadDir(installPath)
if statErr != nil && !os.IsNotExist(statErr) {
return statErr
}
if 0 < len(entries) {
return errors.New("marketplace package install path already exists")
}
}
tmpPackage := filepath.Join(util.TempDir, "bazaar", "package")
// ... unzipping code ...
// Validate consistency between package JSON name and requested packageName
jsonFileName, ok := packageManifestNames[pkgType]
if !ok {
return errors.New("invalid marketplace package type")
}
pkg, parseErr := ParsePackageJSON(filepath.Join(srcPath, jsonFileName))
if parseErr != nil || nil == pkg {
return errors.New("marketplace package manifest not found or invalid")
}
if packageName != pkg.Name {
return fmt.Errorf("marketplace package name mismatch: expected [%s], got [%s]", packageName, pkg.Name)
}
if err = filelock.Copy(srcPath, installPath); err != nil {
return
}
return nil
}To exploit this vulnerability, an attacker must craft an installation request targeted at the SiYuan API endpoint responsible for Bazaar package installations.
The attacker prepares a malicious package archive containing a plugin.json where name is set to attacker-plugin. Inside index.js, the attacker embeds arbitrary code meant to execute within the context of the application runtime.
The attacker sends an HTTP POST request specifying packageName: "target-legitimate-plugin" and repoURL: "https://attacker.example.com/malicious-repo". The backend processes the request, downloads the payload, and copies index.js into the path corresponding to target-legitimate-plugin.
When SiYuan initializes or reloads the target-legitimate-plugin, the newly overwritten index.js executes. Because SiYuan plugin scripts operate within the client/desktop application execution environment, this grants code execution capabilities under the privilege context of the running user.
The CVSS v3.1 base score for CVE-2026-62204 is rated at 6.6 (Medium) with vector CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:L/I:H/A:L.
Successful exploitation results in severe integrity impact because core files of established plugins can be altered without administrative or file-system-level warnings. An attacker achieves persistent code execution across application restarts.
Confidentiality and availability impacts are assessed as low, as execution is contingent upon user interaction or application reload within local user context. The scope is marked as changed due to the boundary crossing between user-supplied data input and installed system extension modules.
The primary remediation path is updating the SiYuan application to version 3.7.4 or later (or release v3.8.0+), which includes patch commit 26ccb40d390eb7d9b04673629a58ab1d69cc7e53.
If immediate upgrading is not feasible, restrict network access to the API port binding (default localhost) and ensure browser same-origin policies prevent unauthorized cross-origin requests from reaching local SiYuan kernel endpoints.
Regularly inspect the data/plugins/ directory to verify package checksums and detect unauthorized modifications to index.js or configuration files across installed extensions.
CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:L/I:H/A:L| Attribute | Detail |
|---|---|
| CWE ID | CWE-345 |
| Attack Vector | Local / API Request |
| CVSS v3.1 Score | 6.6 (Medium) |
| CVSS v4.0 Score | 5.9 (Medium) |
| EPSS Score | 0.00094 (0.56th percentile) |
| Exploit Status | Proof of Concept / Advisory Stage |
| CISA KEV Status | Not Listed |
In obsidian-tc versions 1.0.1 through 1.31.3, memory lifecycle tools fail to validate note ownership prior to rematerializing Markdown files and execute non-atomic SQLite database mutations. An authorized caller can overwrite arbitrary note bodies on disk and cause persistent desynchronization between the database memory graph and physical vault files.
A high-severity authorization bypass vulnerability in obsidian-tc allows clients to bypass Human-In-The-Loop (HITL) confirmation prompts over Streamable HTTP deployments. Due to incomplete validation of returned prompt responses, an attacker echoing a signed requestState token can force execution of destructive vault operations even if a human user declines or cancels the prompt.
A Denial of Service (DoS) vulnerability in pypdf versions prior to 6.21.0 allows remote attackers to cause high CPU and memory resource exhaustion by supplying PDF files containing oversized or deeply nested arrays, dictionaries, or content streams.
An uncontrolled resource consumption and inefficient algorithmic complexity vulnerability in pypdf prior to version 6.21.0 allows remote attackers to trigger application-level denial-of-service (DoS) via crafted PDF form field hierarchies.
Nuxt versions 3.11.0 through 3.21.3 and 4.0.0 through 4.4.3 contain an interpretation conflict between the route rules matching engine and the core page routing mechanism. By submitting percent-encoded request path segments, unauthenticated attackers can bypass route rules, including appMiddleware authorization guards, and access rendered server-side page payloads.
A Cross-Site Scripting (XSS) vulnerability exists in Nuxt when configured with pages disabled (pages: false). ASCII C0 control characters prefixing javascript: URIs bypass internal protocol classification in the fallback router, allowing unauthenticated attackers to execute arbitrary script in the victim's origin context upon user interaction.