Jun 18, 2026·6 min read·17 visits
A local symlink-following vulnerability in BBOT's github_workflows module allows an attacker sharing the scan directory to overwrite arbitrary local files when a victim scans a targeted repository.
The github_workflows module in BBOT (Black Lantern Security OSINT framework) versions 2.0.0 through 2.8.4 constructs local directory paths from user-controlled repository and owner names without validating for symbolic links. A local attacker sharing the scan directory can pre-plant a symlink at the predictable output path, forcing BBOT to write downloaded workflow artifacts or run logs to an arbitrary location on the filesystem.
BBOT is an active OSINT and reconnaissance framework used to gather threat intelligence and map external attack surfaces. The github_workflows module within BBOT retrieves workflow run logs and artifacts from a target GitHub repository. This functionality is exposed to the local filesystem through automatic directory creation and file storage procedures.
To store these gathered resources locally, the module organizes downloads based on the target repository owner and repository name. Because these names are determined dynamically during a scan, they serve as user-controlled variables. When configuring directories to save these files, the framework relies on path construction techniques that do not verify the underlying file types.
This lack of verification introduces an attack surface classified as CWE-59: Improper Link Resolution Before File Access ('Link Following'). A local adversary who has write access to the shared scan directory or a predictable public path (e.g., /tmp) can create symbolic links targeting sensitive system resources. When the victim initiates a scan, the framework resolves these links blindly, allowing arbitrary file writes to occur.
The root cause of CVE-2026-12567 lies in the omission of path-sanitization checks prior to invoking directory creation and file-write calls. Specifically, the framework constructs target paths by joining a trusted base directory with variables retrieved from GitHub API responses or user configurations.
The vulnerable execution flow follows this sequence:
folder = self.output_dir / owner / repo
self.helpers.mkdir(folder)
file_destination = folder / filenameThe self.helpers.mkdir utility creates the requested folder structure recursively. However, it fails to verify whether any intermediate directory component (such as owner or repo) is an existing symbolic link pointing outside the designated output_dir boundary.
By leveraging this behavioral gap, a local attacker can exploit predictable paths. Because the framework organizes output directories using the format {output_dir}/{owner}/{repo}, the exact layout of the target directory is known beforehand. This allows the pre-creation of symlinks that route the eventual file creation payloads toward sensitive locations, bypassing normal filesystem organizational limits.
In BBOT versions prior to 2.8.5, paths were created directly using the pathlib division operator without path-element inspection. The fix introduced in commit 16d9c42b6c591c07ee94d260cb0588e72d4eae2b mitigates this weakness by recursively inspecting each subdirectory component starting from the safe base path.
Below is the comparison between the vulnerable and patched file operations:
# Vulnerable Path construction (bbot/modules/github_workflows.py)
async def download_run_logs(self, owner, repo, run_id):
folder = self.output_dir / owner / repo
self.helpers.mkdir(folder) # Vulnerable: Creates path recursively without link checks
filename = f"run_{run_id}.zip"
file_destination = folder / filenameThe patch introduces the _check_output_path helper function to validate path components individually:
# Patched Implementation (bbot/modules/github_workflows.py)
def _check_output_path(self, folder):
try:
# Ensure the target folder is a child of the output_dir
rel = folder.relative_to(self.output_dir)
except ValueError:
return False
current = self.output_dir
# Walk down the relative components and verify none are symlinks
for part in rel.parts:
current = current / part
if current.is_symlink():
self.warning(f"Refusing to write through symlink: {current}")
return False
return TrueWhile this fix successfully blocks basic symlink redirection, a critical analysis reveals two limitations:
Time-of-Check to Time-of-Use (TOCTOU): The framework performs the validation in Python before invoking the mkdir and file-write commands. In an active, multi-user shared filesystem, an attacker could monitor directory modifications. Using tools like inotify, the attacker can swap the verified directory with a symlink immediately after _check_output_path returns True but before the write operation finishes.
Unchecked Base Directory: The validation assumes self.output_dir itself is secure and not a symlink. If the parent or base scan output directory is compromised, the logic can be subverted.
Hardlink Attacks: The check depends on is_symlink(), which ignores hardlinks. If hardlink protection (fs.protected_hardlinks) is not enabled at the operating system level, an attacker might still attempt link attacks on files sharing the same physical partition.
To successfully execute a symlink attack against a BBOT instance using the github_workflows module, the following conditions must be met:
/tmp or a shared group folder.The attack flow is visualized below:
An attacker begins by pre-creating the target directory structure. For example, if the victim is expected to scan a repository named testrepo owned by testowner, the attacker constructs the path inside the target scan folder:
mkdir -p /tmp/bbot_output/testowner
ln -s /home/victim/.ssh/authorized_keys /tmp/bbot_output/testowner/testrepoWhen the victim runs BBOT, the module queries the GitHub API, retrieves run logs, and writes them to the target destination. Because the symlink points to /home/victim/.ssh/authorized_keys, the written data (in this case, compressed zip logs or text log formats) is directed into the SSH configuration file, corrupting it or appending uncontrolled text.
The impact of CVE-2026-12567 is limited compared to remote code execution bugs, resulting in a CVSS v3.1 score of 2.2 (Low). The vector breakdown is CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:L/A:N.
The attack vector is restricted to local system access (AV:L), and requires high attack complexity (AC:H) due to the timing and naming coordination required. The attacker must anticipate the exact GitHub repository and owner configuration targeted by the victim.
While the integrity impact is rated Low (I:L), successful exploitation results in writing user-controlled GitHub artifacts and logs into administrative or target files. An attacker could overwrite configuration files, system scripts, or security keys. This could potentially disrupt local services or allow the attacker to manipulate environmental variables or access credentials in subsequent phases of an intrusion.
CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
BBOT Black Lantern Security | >= 2.0.0, <= 2.8.4 | 2.8.5 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-59 |
| Attack Vector | Local |
| CVSS v3.1 Score | 2.2 |
| EPSS Score | 0.0009 (Percentile: 0.60%) |
| Impact | Low Integrity Impact (Unsanitized local file write) |
| Exploit Status | Proof of Concept (PoC) available in official test suite |
| KEV Status | Not listed in CISA KEV |
The software attempts to access a file based on a filename, but it does not properly associate the name with the intended file entity, which can allow an attacker to substitute a different file (e.g. via symbolic links).
An authentication bypass in the SiYuan personal knowledge management system before version 3.7.0 exposes a dynamic icon rendering endpoint. This endpoint processes client-supplied Go template directives. By submitting a crafted request, an unauthenticated remote attacker can leverage registered database template functions to execute arbitrary read-only SQL queries and exfiltrate workspace contents.
CVE-2026-54069 is a critical authentication bypass vulnerability in the SiYuan Note personal knowledge management system. The flaw is located in the HTTP server's middleware handling API authorization, which unconditionally trusts requests carrying a 'chrome-extension://' scheme in the Origin HTTP header, granting administrative access without validating API tokens.
CVE-2026-54089 is a critical authentication bypass vulnerability in File Browser affecting instances configured with proxy-based authentication. An unauthenticated remote attacker with direct network access can impersonate arbitrary users or register new accounts by spoofing configured HTTP headers.
The malicious Cargo package 'exploration' was uploaded to the crates.io registry. During compilation or package import, the crate executes code designed to establish an outbound TCP/HTTP connection, download an external second-stage binary, and execute the binary locally on the host machine. This creates an unauthenticated remote code execution vector impacting developer environments and continuous integration pipelines.
CVE-2026-54088 is a critical command injection vulnerability in File Browser prior to version 2.63.6. When Hook Authentication is enabled, the application interpolates unsanitized credentials into a shell command, allowing unauthenticated remote code execution.
An authenticated remote code execution vulnerability exists in NotrinosERP (versions up to and including 1.0.0) within the Human Resource Management (HRM) module. Users with employee management permissions can upload arbitrary file types, including PHP scripts, which are written directly to a web-accessible directory. This allows for arbitrary code execution in the context of the web-server user.