khashayar@security:~
$
$
$

Khashayar Nazarkardeh

Cybersecurity Leader specializing in threat hunting, penetration testing, and purple team operations. I detect adversary activity early and drive the mitigation and remediation work that closes the gap before it becomes an incident. Skilled in deploying and tuning endpoint detection and response platforms to strengthen visibility across complex environments. My expertise extends into data loss prevention, AI and LLM risk assessment, and governance mapped to frameworks including MITRE ATT&CK, MITRE ATLAS, and the OWASP LLM Top 10. I study how adversaries exploit systems, then translate those findings into the controls, policies, and risk decisions organizations need to operate securely.

In the field

Sole security professional carrying company-wide responsibility across penetration testing, AI governance, and data protection.

Technical Lead - Cybersecurity
SIR Corp · March 2025 – Present

Owns company-wide penetration testing, AI governance, and tool-approval authority, with primary responsibility for the organization's data loss prevention program and oversight of managed detection and response operations.

  • Increased vulnerability scan visibility to 100% across the environment
  • Led company-wide implementation of DMARC and DLP programs
  • Improved Active Directory security hygiene by 22%
  • Authored gold-standard incident response playbooks derived from tabletop exercises
  • Directed company-wide penetration testing across multiple environments and built corresponding remediation plans
Cybersecurity Analyst
FGF Brands · August 2022 – March 2025
  • Performed thorough vulnerability assessments to identify network, application, and system security weaknesses
  • Executed controlled penetration tests to simulate cyber-attacks, exploiting vulnerabilities to evaluate security defences
  • Analyzed findings from penetration tests and provided actionable security recommendations to improve overall security posture
  • Worked closely with Infrastructure and security teams to implement security measures and verify control effectiveness post-remediation
  • Conducted incident investigations on EDR tools
  • Performed threat hunting on the network to detect, isolate, and provide recommendations on threats
  • Provided proactive security investigation and searches across the environment to detect malicious activity
  • Maintained technical proficiency, sharing knowledge firm-wide through tool development, template enhancements, and methodology improvements
  • Identified and implemented improvements in existing processes and procedures
  • Managed DNS records for domains, and SPF, DKIM, and DMARC records for email fraud defence
  • Monitored sign-in logs and email activity, taking action on suspicious behavior
Governance, Risk and Compliance (GRC) Analyst
Reev Tech · September 2020 – June 2022
  • Assisted the Cybersecurity Manager in the execution of security projects
  • Prepared monthly schedules for organizational cybersecurity awareness programs
  • Communicated identified risks to key stakeholders to initiate and drive risk remediation
  • Performed network vulnerability scans and security assessments
  • Provided secure design consulting services on application development projects
Security Operations Centre (SOC) Analyst
Hadafeno Group · September 2019 – September 2020
  • Monitored and analyzed cybersecurity events using Splunk (SIEM), IDS, McAfee antivirus, and other tools
  • Escalated incidents to the L2 SOC team when relevant
  • Analyzed phishing emails reported by internal end-users
  • Triaged security events and incidents, detected anomalies, and reported remediation actions
  • Worked closely with other IT groups to maintain a high level of IT service for internal and external clients
IT Networking Technician
Yekshow Academy · September 2017 – September 2019
  • Installed numerous network devices including routers, switches, controllers, and Wi-Fi APs
  • Configured routers, switches, and controllers to clients' requirements
  • Installed SSDs, RAM, and disk drives
  • Maintained thorough data backup checks on client servers remotely
  • Helped plan and support software and hardware upgrades
Research and Teaching Assistant
Amir Kabir University of Technology · September 2016 – June 2018
  • Developed a program for steganography in images and text files using Python
  • Researched Optical Character Recognition (OCR) for embedding and extracting messages in a cover PDF
  • Investigated sound waves for steganography in cover voices
  • Co-authored the resulting paper: "A New Method for PDF Steganography in Justified Texts"

Research & Publications

Peer-reviewed contributions to the information security field.

JOURNAL OF INFORMATION SECURITY AND APPLICATIONS · 2019
A New Method for PDF Steganography in Justified Texts

Introduces a text steganography method that hides data within justified PDF text by exploiting the variable spacing text editors insert to remove ragged edges. The secret message is compressed with Huffman coding, then embedded by selectively replacing justification spaces with normal spaces across chosen host lines, with the scheme keyed for each use to strengthen communication security. Compared to prior text-based steganography approaches, the method embeds a higher information payload without altering the cover file's size, requires no electronic file exchange between parties, and remains recoverable even from a printed copy.

View publication (DOI) →

Capabilities with evidence

Offensive security and AI security, backed by hands-on lab work and applied engagement experience.

AI & LLM Security

  • Prompt injection & jailbreak analysis
  • RAG pipeline exploitation
  • MCP / agentic tool-abuse assessment
  • MITRE ATLAS threat mapping

Offensive Security

  • Penetration testing (web, network, AD)
  • Privilege escalation chains
  • Red team methodology
  • Vulnerability research

Threat Hunting & Detection

  • Hypothesis-driven hunting across EDR and SIEM telemetry to surface adversary activity that evades automated detection
  • MITRE ATT&CK-mapped detection engineering and coverage analysis
  • Purple team exercises bridging red team findings into blue team detection improvements
  • Incident triage, containment guidance, and remediation planning following confirmed detections

Governance & Risk

  • AI policy & tool approval frameworks
  • DLP program design
  • Business impact / risk translation
  • Compliance mapping (OWASP, NIST AI RMF)

Security Research & Community

  • Maintains an active research practice tracking emerging vulnerabilities and adversary TTPs
  • Engaged with the security research community, exchanging insights with practitioners on X and through TASK monthly conference discussions
  • Regularly solves offensive security challenge labs on the OffSec platform to keep hands-on skills sharp against evolving attack techniques

Certifications

CBBH
Certified Bug Bounty Hunter
✓ verified
CPTS
Certified Penetration Testing Specialist
✓ verified
CWES
Certified Web Exploitation Specialist
✓ verified
OSAI
OffSec AI Red Teamer (AI-300)
◐ in progress
M.S.
Cryptography & Information Security
✓ completed

Field Notes

Original perspectives, vulnerability research, and threat hunting notes from the field, not case studies of confidential work.

PERSPECTIVES · DATA PROTECTION
Why DLP Needs a New Foundation in the AI Era

Data loss prevention was built for a world where humans moved data — copying a file, attaching a document to an email, uploading to a personal drive. Every major DLP program in production today still assumes that model. But that world is gone. AI copilots now read entire mailboxes to draft a reply. Agentic tools summarize confidential documents on request. Employees paste proprietary code into public LLM chat windows without a second thought. None of this looks like the exfiltration patterns legacy DLP was designed to catch, and most organizations are only starting to notice the gap.

The problem isn't the AI tools. It's the missing foundation underneath them. You cannot protect what you haven't classified. Before any policy, any blocking rule, any endpoint control can work, an organization needs a real answer to a basic question: what is this data, and how sensitive is it? Most companies adopting AI tools today don't have that answer at scale. Labels are inconsistent, ownership is unclear, and sensitive data sits mixed in with everything else — which means AI tools reading "all available context" are, by definition, reading things they shouldn't.

Classification has to come first. Not as a compliance checkbox, but as living infrastructure — data labeled consistently at creation, ownership assigned, sensitivity tiers that actually mean something to the tools enforcing them downstream. Skip this step and every control built on top of it is guessing.

Then protection has to be layered, not singular. No single control catches everything an AI-augmented workflow can do with data. Classification tells you what matters. Endpoint policy governs what a device or application is allowed to do with it. Network and cloud monitoring catch what slips past both. Each layer exists because the others will eventually fail or be bypassed — by a misconfigured integration, a compromised account, or simply a tool doing exactly what it was asked to do with data it was never meant to see.

This is the shift security leaders need to make: DLP is no longer a tool you deploy once. It's a foundation you maintain continuously, because the definition of "movement" now includes an AI model reading, summarizing, and acting on data — not just a person sending it somewhere.

The organizations that get ahead of this aren't the ones with the most tools. They're the ones who classify first, control second, and monitor third — in that order, every time.

CVE RESEARCH · CVE-2025-2945
pgAdmin 4: When a Boolean Flag Becomes Remote Code Execution
CVSS 9.9 (Critical) · pgAdmin 4 versions 8.10–9.1 · Fixed in 9.2 (April 4, 2025)
Proof-of-concept exploit code for this vulnerability is published on my GitHub. github.com/Khashayarnzk →

TL;DR

CVE-2025-2945 is a critical remote code execution vulnerability in pgAdmin 4, the most widely used open-source administration platform for PostgreSQL. An authenticated user could turn a simple boolean flag in the Query Tool into arbitrary Python code execution on the server, because the flag was being parsed with Python's eval() instead of an actual boolean check. The fix, once you see it, is a single line, but the path to that line says a lot about how RCE vulnerabilities are actually born: not from exotic deserialization chains, but from a developer reaching for a quick shortcut that happened to also be a code execution primitive.

Background

pgAdmin 4 is the de facto standard web interface for managing PostgreSQL databases, used by DBAs, developers, and platform teams to run queries, inspect schemas, and administer production data through a browser instead of a terminal. Its Query Tool is the core of that experience: a SQL editor that tracks transaction state (has this query been committed? is autocommit on?) and ships that state back and forth between the JavaScript frontend and the Python/Flask backend on every request. That transaction-state handshake is exactly where this vulnerability lived. Any interface that manages live database transactions for an authenticated user is, almost by definition, a high-value target: it sits adjacent to the data it's meant to protect, and it's usually reachable from wherever the DBA's browser is, which in production environments is often broader network access than the database itself allows.

Root Cause

The vulnerable code lived in web/pgadmin/tools/sqleditor/__init__.py, inside start_query_download_tool():

# Vulnerable (pgAdmin <= 9.1)
if key == 'query_commited':
    query_commited = (
        eval(value) if isinstance(value, str) else value
    )

query_commited is meant to be a simple boolean: did the frontend already commit this transaction, yes or no. The frontend sends it as a string, "true" or "false", and the backend needed to turn that string into a Python bool. Instead of writing an explicit check, the code passed the string straight into eval().

This is a subtly different failure than most public writeups describe. It's not deserializing a complex object and not processing a JSON payload; it's using eval() as a lazy type-coercion shortcut, on the (false) assumption that the input would only ever be the literal string "true" or "false". Since eval() executes as Python, not as a boolean parser, any string is fair game: __import__('os').system('id') evaluates exactly as validly as True does.

The same anti-pattern appeared a second time in web/pgacloud/providers/google.py, inside the Cloud Deployment module's Google provider:

# Vulnerable
high_availability = (
    'REGIONAL' if eval(args.high_availability) else 'ZONAL'
)

Same shape, same root cause: a value that should have been coerced to a boolean was evaluated as code instead. Two endpoints, one underlying mistake, made independently by different code paths, which is itself worth noting, since it suggests the pattern wasn't a one-off typo but something close to a house convention for handling stringly-typed booleans.

The fix, shipped in pgAdmin 9.2, replaced eval() with an actual string comparison in both places:

# Fixed (pgAdmin 9.2+)
query_commited = (
    value.lower() in ('true', '1') if isinstance(value, str) else value
)

No parser, no library, no complexity, just doing the boolean check the code should have done from the start.

Exploitation Logic

The vulnerability is authenticated: an attacker needs a valid pgAdmin session before reaching the vulnerable code path. That requirement matters for accurate risk assessment: this is not a pre-auth RCE, and its CVSS 9.9 score reflects the severity of impact, not ease of unauthenticated access. Given how routinely admin interfaces end up secured with weak or default credentials, though, "authenticated" is a much lower bar in practice than it sounds on paper.

Once authenticated, reaching start_query_download_tool() requires an active Query Tool transaction. pgAdmin's SQL editor is namespaced by a transaction ID, and that transaction has to be bound to a registered server and database connection before the download endpoint will process a request at all. This isn't an incidental detail; it means an attacker needs at least one database server already registered in the target pgAdmin instance. In deployments where pgAdmin is pre-configured with one or more saved server connections, which is extremely common in real environments, this precondition is trivially met.

From there, the attacker submits a POST request to /sqleditor/query_tool/download/<trans_id> with a crafted query_commited value, not "true" or "false", but a Python expression with a side effect. The backend hands that string to eval() and executes it under the privileges of the pgAdmin service process. The Cloud Deployment path follows the identical logic through /cloud/deploy and the high_availability parameter, for accounts with access to that module.

Vulnerability Class

This is CWE-95 (Eval Injection), but it's worth being precise about which flavor. The more commonly discussed eval-injection bugs involve deserializing attacker-controlled objects (think Python pickle, or eval() used to parse what should have been JSON). This one is narrower and, in some ways, more mundane: eval() used purely as a boolean type-coercion shortcut. It's the same class of mistake that shows up whenever a developer reaches for eval() to parse a stringly-typed flag from a query string or form field instead of writing value.lower() == 'true', a one-line fix that's easy to skip past in code review because the call site looks so small.

Detection Guidance

Defenders monitoring pgAdmin deployments should watch for:

  • POST requests to /sqleditor/query_tool/download/<trans_id> or /cloud/deploy where the query_commited or high_availability parameter is anything other than a literal "true", "false", "1", or "0".
  • Presence of Python builtins or execution primitives, including __import__, os.system, subprocess, eval, exec, open(, inside those parameter values. This is a near-certain exploitation signature; there's no legitimate reason for a boolean field to contain any of these strings.
  • Unexpected child processes spawned by the pgAdmin service account, particularly shell interpreters (/bin/sh, /bin/bash) or network utilities (nc, curl, wget): the pgAdmin process has no legitimate reason to spawn either.
  • WAF/reverse-proxy rules in front of pgAdmin instances can pattern-match these parameter values directly, since the vulnerable fields are well-defined and narrow.

Remediation

  • Upgrade to pgAdmin 4 version 9.2 or later. The patch is a minimal, low-risk one-line change per endpoint, so there's no operational reason to delay applying it.
  • Where immediate patching isn't possible, restrict network access to pgAdmin to trusted, authenticated networks only (VPN or internal-only access). This vulnerability requires authentication, so reducing exposure to credential-guessing and reducing the population of accounts that can reach the interface both meaningfully lower risk.
  • Disable or restrict the Cloud Deployment module for accounts that don't need it, closing the second vulnerable path independently of the primary fix.
  • More broadly: any admin interface that accepts stringly-typed flags from a browser is worth an internal audit for the same anti-pattern, since eval() reached for as a coercion shortcut rarely announces itself as dangerous in code review.

MITRE ATT&CK Mapping

  • T1190 (Exploit Public-Facing Application): the eval() injection serves as the initial access/execution vector once authenticated.
  • T1059.006 (Command and Scripting Interpreter: Python): the payload executes as native Python on the target, under the pgAdmin service account.

References

CVE RESEARCH · CVE-2025-10952
ml-logger: Arbitrary File Read to Root via stream_handler
CVSS 5.3 (Medium, in isolation) · ml-logger, all versions up to commit acf255b · No fixed version at disclosure
Proof-of-concept exploit code for this vulnerability is published on my GitHub. github.com/Khashayarnzk →

TL;DR

ml-logger is an unauthenticated Sanic HTTP service used to ship metrics, logs, and files between ML training jobs and a dashboard. Its /stream endpoint takes a key parameter, joins it directly onto a server-side root directory, and streams the resulting file back with no validation and no authentication in front of it. The published CVSS score of 5.3 reflects the bug in isolation, but it understates the real blast radius once chained with the sibling /glob endpoint: a single crafted request retrieved root's SSH private key directly, turning an unauthenticated HTTP call into full root compromise.

Background

ml-logger exposes a small file-broker API alongside its metrics-logging functionality: /glob to enumerate files matching a pattern, and /stream to read one back. The intent is legitimate, letting a remote training job or dashboard pull down checkpoint files, logs, or config without SSH access, but the implementation trusts client-supplied paths entirely. This is a common pattern in MLOps tooling: infrastructure built for a trusted, single-tenant research environment gets deployed as though it were a hardened multi-tenant service, without an authentication layer or a threat model that assumes an adversarial network position.

Root Cause

From the disclosed source (ml_logger/server.py):

async def stream_handler(self, req):
    import sanic
    if not req.json:
        msg = f"request json is empty: {req.text}"
        return sanic.response.text(msg)
    load_entry = LoadEntry(**req.json)
    path = self.abs_path(load_entry.key)
    return await sanic.response.file_stream(path)

load_entry.key is attacker-controlled and passed straight into self.abs_path(), then directly into sanic.response.file_stream(), with no allow-list, no realpath containment check, and no rejection of absolute paths or traversal sequences. The maintainer's own glob_handler does reject absolute paths and traversal, but stream_handler doesn't share that validation. A doubled leading slash was enough to defeat the relative-path assumption baked into the join logic: two endpoints with inconsistent path handling, one restrictive and one not, is the actual exploitable gap, independent of either check being individually correct.

Exploitation Logic

The service typically listens on two ports: one serving the dashboard SPA (catch-all routing that returned index.html for every path, including plausible API guesses, a false negative that cost real time during recon), and one serving the actual JSON API. The backend was identified by a 405 on a GET to /glob, with the Allow header confirming POST.

Guessing JSON field names against /glob produced nothing but 500s, since the handler throws on any shape it doesn't expect. The working schema came from the public vulnerability report rather than black-box guessing:

curl -s -X POST -H "Content-Type: application/json" \
  -d '{"query": "/etc/*", "wd": "/", "start": 0, "stop": 9999}' \
  http://TARGET:8081/glob

This confirmed unauthenticated directory enumeration outside any intended log root. Reading the target file via /stream (a GET request carrying a JSON body) used a doubled leading slash as the key detail, a single leading slash returned empty, consistent with the join logic silently swallowing it, while a doubled one broke containment:

curl -s -X GET -H "Content-Type: application/json" \
  -d '{"key":"//root/.ssh/id_rsa","type":""}' \
  http://TARGET:8081/stream

The response was root's raw OpenSSH private key. Saved locally, permissions corrected, and used directly to SSH in as root, an unauthenticated HTTP request turned into an authenticated root shell with zero credentials required at any step.

Vulnerability Class

A textbook CWE-22/CWE-200 hybrid: unsanitized path input leading to arbitrary file read. This pattern is common across the MLOps tooling category, logging and metrics servers, experiment trackers, and model registries frequently expose file-serving endpoints as a convenience feature, and that convenience feature is disproportionately likely to be the least-reviewed code path in the project. The glob/stream pairing here also illustrates why per-endpoint validation isn't sufficient on its own: the glob handler's traversal check gave a false sense that the file-access surface was already covered.

Detection Guidance

  • Alert on key/path/file-style JSON parameters containing .., doubled leading slashes, or absolute path prefixes like /etc or /root directed at logging or metrics service ports.
  • File integrity/access monitoring on SSH keys and credential files should flag reads from a process identity associated with a logging daemon rather than an interactive shell or expected backup job.
  • ml-logger logs almost nothing useful by default, treat any exposed instance as a blind spot and compensate at the network layer until instrumented.
  • Fingerprint the dashboard SPA and the 405/Allow: POST signature on /glob as an indicator this service is reachable at all, it should never be internet- or flat-network-exposed without authentication in front of it.

Remediation

  • Do not expose ml-logger to any untrusted network. It has no built-in authentication; if it must be reachable, place it behind an authenticating reverse proxy at minimum.
  • Add compensating validation at the reverse-proxy layer blocking absolute paths, traversal sequences, and doubled slashes in the JSON body, since the vulnerable parameter travels in the body rather than the URL path.
  • Run the service under an unprivileged, dedicated account with no access to sensitive directories, a single control that would have fully contained this chain regardless of the code-level bug.
  • As of disclosure there is no fixed version for this rolling-release project; pin to a patched fork or vendor a fix that enforces a shared, tested path-containment check across both handlers.

MITRE ATT&CK / ATLAS Mapping

  • T1552.004 (Unsecured Credentials: Private Keys): the exposed file-read endpoint directly retrieves SSH private keys.
  • T1083 (File and Directory Discovery): via the /glob endpoint.
  • T1078 (Valid Accounts): the resulting root SSH access.
  • MITRE ATLAS AML.T0024 (Exfiltration via ML Inference API): the file-serving endpoint sits directly on the ML training/logging pipeline, making this an MLOps-adjacent exfiltration path rather than a purely generic webapp bug.

References