endpoint security

Implementing USB Device Control Policy

Implements USB device control policies to restrict unauthorized removable media access on endpoints, preventing data exfiltration and malware introduction via USB devices. Use when deploying device control via Group Policy, Intune, or EDR platforms to enforce USB restrictions. Activates for requests involving USB control, removable media policy, device control, or data loss prevention via USB.

data-loss-preventiondevice-controlendpointremovable-mediausb-control
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

Use this skill when:

  • Restricting USB storage devices to prevent data exfiltration or malware introduction
  • Implementing device control policies via GPO, Intune, or EDR device control modules
  • Creating USB whitelists for authorized devices while blocking all others
  • Meeting compliance requirements for removable media control (PCI DSS, HIPAA)

Do not use for network-based DLP or cloud storage restrictions.

Prerequisites

  • Active Directory GPO or Microsoft Intune for policy deployment
  • Device Instance IDs of authorized USB devices
  • EDR with device control module (CrowdStrike, Microsoft Defender for Endpoint)
  • Understanding of USB device classes (mass storage, HID, printer, etc.)

Workflow

Step 1: Inventory Current USB Usage

# Enumerate currently connected USB devices
Get-PnpDevice -Class USB | Select-Object InstanceId, FriendlyName, Status
 
# Query USB storage history from registry
Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR\*\*" |
  Select-Object FriendlyName, ContainerID, HardwareID
 
# Collect USB usage across fleet (via EDR or scripts)
# CrowdStrike: Investigate → USB Device Activity
# MDE: DeviceEvents | where ActionType == "UsbDriveMounted"

Step 2: Configure GPO Device Control

Computer Configuration → Administrative Templates → System → Removable Storage Access
 
- All Removable Storage classes: Deny all access → Enabled
  (Block read AND write for all removable storage)
 
OR for granular control:
- CD and DVD: Deny read access → Enabled
- Removable Disks: Deny write access → Enabled (read-only USB)
- Tape Drives: Deny all access → Enabled
- WPD Devices: Deny all access → Enabled
 
To allow specific approved USB devices:
Computer Configuration → Administrative Templates → System → Device Installation
  → Device Installation Restrictions
 
- Prevent installation of devices not described by other policy settings → Enabled
- Allow installation of devices that match any of these device IDs → Enabled
  Add approved Device IDs: USB\VID_0781&PID_5583 (example: SanDisk Cruzer)

Step 3: Deploy via Microsoft Defender for Endpoint

<!-- MDE Device Control policy (XML format) -->
<PolicyGroups>
  <Group Id="{d9a81dc0-1234-5678-9abc-def012345678}"
    Type="Device" Name="Approved USB Devices">
    <MatchClause>
      <MatchType>VID_PID</MatchType>
      <MatchData>0781_5583</MatchData> <!-- SanDisk -->
    </MatchClause>
  </Group>
</PolicyGroups>
 
<PolicyRules>
  <Rule Id="{rule-guid}" Name="Block unapproved USB storage">
    <IncludedIdList>
      <PrimaryId>RemovableMediaDevices</PrimaryId>
    </IncludedIdList>
    <ExcludedIdList>
      <GroupId>{d9a81dc0-1234-5678-9abc-def012345678}</GroupId>
    </ExcludedIdList>
    <Entry>
      <Type>Deny</Type>
      <AccessMask>63</AccessMask> <!-- All access -->
      <Options>4</Options> <!-- Show notification -->
    </Entry>
  </Rule>
</PolicyRules>

Step 4: Audit and Monitor

# Monitor USB events in SIEM:
# Windows Event ID 6416 - New external device recognized
# Windows Event ID 4663 - File access on removable media
# MDE: DeviceEvents where ActionType contains "Usb"
 
# Generate USB activity reports monthly
# Track: blocked attempts, approved device usage, exception requests

Key Concepts

Term Definition
VID/PID Vendor ID and Product ID that uniquely identify USB device models
Device Instance ID Unique identifier for a specific physical USB device
Device Control EDR/endpoint feature restricting device access based on type, vendor, or serial number
USB Class USB device category (mass storage 08h, HID 03h, printer 07h)

Tools & Systems

  • Microsoft Defender Device Control: MDE module for USB restriction policies
  • CrowdStrike Falcon Device Control: EDR-based USB policy enforcement
  • Group Policy (Removable Storage Access): Built-in Windows USB restriction via GPO
  • Endpoint Protector: Third-party device control and DLP solution

Common Pitfalls

  • Blocking all USB without exception: Keyboards and mice are USB HID devices. Block only mass storage class, not all USB.
  • Not communicating policy to users: USB blocks without user notification generate helpdesk tickets. Display a notification explaining the policy.
  • Ignoring USB-C and Thunderbolt: Modern devices use USB-C for docking, charging, and storage. Policies must distinguish between USB storage and USB peripherals.
  • No approved device process: Users with legitimate USB needs (presentations, field data collection) require an exception process with approved, encrypted devices.
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md6.1 KB

API Reference: USB Device Control Policy Audit

Libraries Used

Library Purpose
subprocess Execute PowerShell, udevadm, and registry query commands
json Parse device inventory and policy status
platform Detect operating system for platform-specific checks
re Parse device IDs and USB vendor/product codes

Installation

# No external packages — uses standard library and OS tools

Windows USB Device Audit

List Connected USB Devices (PowerShell)

import subprocess
import json
 
def list_usb_devices_windows():
    cmd = [
        "powershell", "-Command",
        "Get-PnpDevice -Class USB | Select-Object Status, Class, FriendlyName, InstanceId | ConvertTo-Json"
    ]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
    return json.loads(result.stdout) if result.stdout else []

Check USB Storage Policy (Registry)

def check_usb_storage_policy():
    """Check if USB mass storage is disabled via registry."""
    cmd = [
        "powershell", "-Command",
        'Get-ItemProperty -Path "HKLM:\\SYSTEM\\CurrentControlSet\\Services\\USBSTOR" -Name Start | Select-Object Start | ConvertTo-Json'
    ]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
    if result.stdout:
        data = json.loads(result.stdout)
        start_value = data.get("Start", 3)
        return {
            "usb_storage_disabled": start_value == 4,
            "registry_value": start_value,
            "policy": "disabled" if start_value == 4 else "enabled",
            "detail": {
                3: "USB storage ENABLED (default)",
                4: "USB storage DISABLED",
            }.get(start_value, f"Unknown value: {start_value}"),
        }
    return {"usb_storage_disabled": False, "error": "Could not read registry"}

Check Group Policy for Removable Storage

def check_gpo_removable_storage():
    """Check GPO settings for removable storage restrictions."""
    policies = {
        "deny_read": r"HKLM\SOFTWARE\Policies\Microsoft\Windows\RemovableStorageDevices\{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}\Deny_Read",
        "deny_write": r"HKLM\SOFTWARE\Policies\Microsoft\Windows\RemovableStorageDevices\{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}\Deny_Write",
        "deny_execute": r"HKLM\SOFTWARE\Policies\Microsoft\Windows\RemovableStorageDevices\{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}\Deny_Execute",
    }
    results = {}
    for name, path in policies.items():
        cmd = ["reg", "query", path.rsplit("\\", 1)[0], "/v", path.rsplit("\\", 1)[1]]
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
        results[name] = "1" in result.stdout if result.returncode == 0 else False
    return results

USB Device History (Windows)

def get_usb_history_windows():
    """List previously connected USB storage devices from registry."""
    cmd = [
        "powershell", "-Command",
        'Get-ItemProperty "HKLM:\\SYSTEM\\CurrentControlSet\\Enum\\USBSTOR\\*\\*" | Select-Object FriendlyName, DeviceDesc, Mfg | ConvertTo-Json'
    ]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
    return json.loads(result.stdout) if result.stdout else []

Linux USB Device Audit

List USB Devices

def list_usb_devices_linux():
    result = subprocess.run(
        ["lsusb"], capture_output=True, text=True, timeout=10
    )
    devices = []
    for line in result.stdout.strip().split("\n"):
        if line:
            devices.append(line.strip())
    return devices

Check USBGuard Policy

def check_usbguard_status():
    """Check if USBGuard is installed and active."""
    # Check service status
    result = subprocess.run(
        ["systemctl", "is-active", "usbguard"],
        capture_output=True, text=True, timeout=10,
    )
    service_active = result.stdout.strip() == "active"
 
    # List current policy rules
    rules = []
    if service_active:
        result = subprocess.run(
            ["usbguard", "list-rules"],
            capture_output=True, text=True, timeout=10,
        )
        rules = result.stdout.strip().split("\n") if result.stdout else []
 
    return {
        "usbguard_installed": service_active or result.returncode != 127,
        "service_active": service_active,
        "policy_rules": len(rules),
        "default_policy": "block" if any("block" in r for r in rules) else "allow",
    }

Check udev Rules for USB Control

def check_udev_rules():
    """Check for USB control udev rules."""
    result = subprocess.run(
        ["find", "/etc/udev/rules.d/", "-name", "*usb*", "-type", "f"],
        capture_output=True, text=True, timeout=10,
    )
    rules_files = result.stdout.strip().split("\n") if result.stdout.strip() else []
    return {"udev_usb_rules": rules_files, "count": len(rules_files)}

Device Whitelist Management

APPROVED_DEVICES = [
    {"vendor_id": "046d", "product_id": "c52b", "name": "Logitech Receiver"},
    {"vendor_id": "0781", "product_id": "5583", "name": "SanDisk Encrypted Drive"},
]
 
def check_against_whitelist(connected_devices, approved=APPROVED_DEVICES):
    approved_ids = {(d["vendor_id"], d["product_id"]) for d in approved}
    findings = []
    for device in connected_devices:
        vid = device.get("vendor_id", "")
        pid = device.get("product_id", "")
        if (vid, pid) not in approved_ids:
            findings.append({
                "device": device.get("name", "Unknown"),
                "vendor_id": vid,
                "product_id": pid,
                "issue": "Device not in approved whitelist",
                "severity": "medium",
            })
    return findings

Output Format

{
  "platform": "windows",
  "usb_storage_disabled": true,
  "gpo_deny_read": true,
  "gpo_deny_write": true,
  "connected_devices": 3,
  "unapproved_devices": 1,
  "historical_devices": 12,
  "findings": [
    {
      "device": "Unknown USB Mass Storage",
      "vendor_id": "0951",
      "product_id": "1666",
      "issue": "Device not in approved whitelist",
      "severity": "medium"
    }
  ]
}
standards.md0.7 KB

Standards & References

Primary Standards

  • NIST SP 800-53 MP-7: Media Use - restricting removable media types and usage
  • PCI DSS 4.0 Req 3.4.2: Restrict removable electronic media for cardholder data
  • CIS Control 10.4: Configure device control to prevent removable media autorun
  • ISO 27001 A.8.3.1: Management of removable media

Supporting References

workflows.md0.7 KB

Workflows

Workflow 1: USB Device Control Deployment

[Audit current USB usage across fleet] → [Identify legitimate USB needs]
  → [Create approved device whitelist] → [Configure block policy with exceptions]
  → [Deploy in audit mode for 2 weeks] → [Review blocked events]
  → [Add missing legitimate devices] → [Switch to enforce mode]
  → [Communicate policy to users] → [Monitor and maintain]

Workflow 2: USB Exception Request

[User requests USB access] → [Verify business justification]
  → [Issue approved encrypted USB device] → [Add device ID to whitelist]
  → [Deploy updated policy] → [Log exception with expiry date]

Scripts 2

agent.py8.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""USB device control policy audit agent.

Audits USB device control policies on Linux and Windows systems by
checking udev rules, USBGuard configuration, Windows Group Policy
settings, and connected device history. Reports unauthorized or
unwhitelisted USB devices.
"""
import argparse
import json
import os
import subprocess
import sys
from datetime import datetime, timezone


def audit_linux_usbguard():
    """Audit USBGuard configuration and rules on Linux."""
    findings = []
    print("[*] Auditing USBGuard configuration...")

    # Check if USBGuard is installed and running
    result = subprocess.run(
        ["systemctl", "is-active", "usbguard"],
        capture_output=True, text=True, timeout=10,
    )
    if result.stdout.strip() == "active":
        findings.append({"check": "USBGuard service", "status": "PASS",
                         "severity": "INFO", "detail": "USBGuard is running"})
    else:
        findings.append({"check": "USBGuard service", "status": "FAIL",
                         "severity": "HIGH", "detail": "USBGuard is not running"})
        return findings

    # List current USB devices and their authorization
    result = subprocess.run(
        ["usbguard", "list-devices"],
        capture_output=True, text=True, timeout=15,
    )
    if result.returncode == 0:
        devices = []
        for line in result.stdout.strip().splitlines():
            parts = line.split()
            if len(parts) >= 3:
                dev_id = parts[0].rstrip(":")
                policy = parts[1]
                name = " ".join(parts[2:])
                devices.append({"id": dev_id, "policy": policy, "name": name})
                if policy == "allow":
                    findings.append({"check": f"USB Device {dev_id}", "status": "INFO",
                                    "severity": "INFO", "detail": f"Allowed: {name}"})
                elif policy == "block":
                    findings.append({"check": f"USB Device {dev_id}", "status": "BLOCKED",
                                    "severity": "INFO", "detail": f"Blocked: {name}"})

    # Check default policy
    result = subprocess.run(
        ["usbguard", "get-parameter", "ImplicitPolicyTarget"],
        capture_output=True, text=True, timeout=10,
    )
    if result.returncode == 0:
        policy = result.stdout.strip()
        if policy == "block":
            findings.append({"check": "Default USB policy", "status": "PASS",
                            "severity": "INFO", "detail": "Default: block (deny by default)"})
        else:
            findings.append({"check": "Default USB policy", "status": "FAIL",
                            "severity": "HIGH",
                            "detail": f"Default: {policy} (should be 'block')"})

    # List rules
    result = subprocess.run(
        ["usbguard", "list-rules"],
        capture_output=True, text=True, timeout=10,
    )
    if result.returncode == 0:
        rules = result.stdout.strip().splitlines()
        findings.append({"check": "USBGuard rules", "status": "INFO",
                        "severity": "INFO", "detail": f"{len(rules)} rules configured"})

    return findings


def audit_linux_udev():
    """Check for USB-related udev rules on Linux."""
    findings = []
    udev_dirs = ["/etc/udev/rules.d", "/lib/udev/rules.d", "/usr/lib/udev/rules.d"]
    usb_rules_found = False

    for udev_dir in udev_dirs:
        if not os.path.isdir(udev_dir):
            continue
        for fname in os.listdir(udev_dir):
            fpath = os.path.join(udev_dir, fname)
            if not os.path.isfile(fpath):
                continue
            try:
                with open(fpath, "r") as f:
                    content = f.read()
                if "usb" in content.lower() and ("authorize" in content.lower() or "block" in content.lower()):
                    usb_rules_found = True
                    findings.append({"check": f"udev USB rule: {fname}", "status": "INFO",
                                    "severity": "INFO", "detail": fpath})
            except (IOError, PermissionError):
                pass

    if not usb_rules_found:
        findings.append({"check": "udev USB rules", "status": "WARN",
                         "severity": "MEDIUM", "detail": "No USB-specific udev rules found"})
    return findings


def list_connected_usb_devices():
    """List currently connected USB devices."""
    devices = []
    if sys.platform == "win32":
        ps_cmd = (
            "Get-PnpDevice -Class USB | "
            "Select-Object InstanceId, FriendlyName, Status, Class | "
            "ConvertTo-Json"
        )
        result = subprocess.run(
            ["powershell", "-Command", ps_cmd],
            capture_output=True, text=True, timeout=30,
        )
        if result.returncode == 0 and result.stdout.strip():
            try:
                raw = json.loads(result.stdout)
                if isinstance(raw, dict):
                    raw = [raw]
                for dev in raw:
                    devices.append({
                        "instance_id": dev.get("InstanceId", ""),
                        "name": dev.get("FriendlyName", "Unknown"),
                        "status": dev.get("Status", ""),
                        "class": dev.get("Class", "USB"),
                    })
            except json.JSONDecodeError:
                pass
    else:
        result = subprocess.run(
            ["lsusb"],
            capture_output=True, text=True, timeout=10,
        )
        if result.returncode == 0:
            for line in result.stdout.strip().splitlines():
                parts = line.split("ID ")
                if len(parts) >= 2:
                    devices.append({
                        "bus_info": parts[0].strip(),
                        "id": parts[1].split()[0] if parts[1].split() else "",
                        "name": " ".join(parts[1].split()[1:]) if len(parts[1].split()) > 1 else "Unknown",
                    })

    return devices


def format_summary(findings, devices):
    """Print audit summary."""
    print(f"\n{'='*60}")
    print(f"  USB Device Control Policy Audit")
    print(f"{'='*60}")
    print(f"  Connected Devices: {len(devices)}")
    print(f"  Policy Findings  : {len(findings)}")

    severity_counts = {}
    for f in findings:
        sev = f.get("severity", "INFO")
        severity_counts[sev] = severity_counts.get(sev, 0) + 1

    pass_count = sum(1 for f in findings if f["status"] == "PASS")
    fail_count = sum(1 for f in findings if f["status"] == "FAIL")
    print(f"  Passed : {pass_count}")
    print(f"  Failed : {fail_count}")

    if devices:
        print(f"\n  Connected USB Devices:")
        for d in devices:
            print(f"    {d.get('name', 'Unknown'):40s} | {d.get('id', d.get('instance_id', 'N/A'))}")

    if findings:
        print(f"\n  Policy Checks:")
        for f in findings:
            icon = "OK" if f["status"] == "PASS" else "!!" if f["status"] == "FAIL" else "--"
            print(f"    [{icon}] {f['check']}: {f.get('detail', '')[:50]}")

    return severity_counts


def main():
    parser = argparse.ArgumentParser(description="USB device control policy audit agent")
    parser.add_argument("--list-devices", action="store_true", help="List connected USB devices")
    parser.add_argument("--output", "-o", help="Output JSON report")
    parser.add_argument("--verbose", "-v", action="store_true")
    args = parser.parse_args()

    findings = []
    devices = list_connected_usb_devices()

    if sys.platform != "win32":
        findings.extend(audit_linux_usbguard())
        findings.extend(audit_linux_udev())

    if not findings:
        findings.append({"check": "USB control policy", "status": "WARN",
                         "severity": "HIGH",
                         "detail": "No USB device control mechanism detected"})

    severity_counts = format_summary(findings, devices)

    report = {
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "tool": "USB Device Control Audit",
        "devices": devices,
        "findings": findings,
        "severity_counts": severity_counts,
        "risk_level": (
            "HIGH" if severity_counts.get("HIGH", 0) > 0
            else "MEDIUM" if severity_counts.get("MEDIUM", 0) > 0
            else "LOW"
        ),
    }

    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2)
        print(f"\n[+] Report saved to {args.output}")
    elif args.verbose:
        print(json.dumps(report, indent=2))


if __name__ == "__main__":
    main()
process.py3.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""USB Device Control Audit - Analyzes USB device activity from endpoint logs."""

import json
import csv
import sys
import os
from collections import Counter, defaultdict
from datetime import datetime


def parse_usb_events(csv_path: str) -> list:
    """Parse USB device events from exported Windows event logs or EDR data."""
    events = []
    with open(csv_path, "r", encoding="utf-8-sig") as f:
        reader = csv.DictReader(f)
        for row in reader:
            events.append({
                "timestamp": row.get("Timestamp", row.get("Date and Time", "")),
                "host": row.get("Computer", row.get("DeviceName", "")),
                "user": row.get("User", row.get("AccountName", "")),
                "action": row.get("Action", row.get("ActionType", "")),
                "device_name": row.get("DeviceName", row.get("FriendlyName", "")),
                "device_id": row.get("DeviceId", row.get("HardwareId", "")),
                "vid_pid": row.get("VID_PID", ""),
                "serial": row.get("SerialNumber", ""),
                "blocked": row.get("Blocked", row.get("ActionType", "")).lower() in ("blocked", "deny", "prevented"),
            })
    return events


def analyze_usb_activity(events: list) -> dict:
    """Analyze USB events for policy violations and usage patterns."""
    analysis = {
        "total_events": len(events),
        "blocked_events": sum(1 for e in events if e["blocked"]),
        "unique_devices": len({e["device_id"] for e in events if e["device_id"]}),
        "devices_by_host": defaultdict(set),
        "top_users": Counter(),
        "blocked_devices": Counter(),
        "allowed_devices": Counter(),
    }

    for event in events:
        if event["host"] and event["device_id"]:
            analysis["devices_by_host"][event["host"]].add(event["device_id"])
        if event["user"]:
            analysis["top_users"][event["user"]] += 1
        if event["blocked"]:
            analysis["blocked_devices"][event.get("device_name", event["device_id"])] += 1
        else:
            analysis["allowed_devices"][event.get("device_name", event["device_id"])] += 1

    analysis["devices_by_host"] = {k: len(v) for k, v in analysis["devices_by_host"].items()}
    return analysis


def generate_report(analysis: dict, output_path: str) -> None:
    """Generate USB activity report."""
    report = {
        "report_generated": datetime.utcnow().isoformat() + "Z",
        "summary": {
            "total_events": analysis["total_events"],
            "blocked": analysis["blocked_events"],
            "unique_devices": analysis["unique_devices"],
        },
        "top_users": dict(analysis["top_users"].most_common(20)),
        "top_blocked_devices": dict(analysis["blocked_devices"].most_common(20)),
        "hosts_with_most_devices": dict(sorted(
            analysis["devices_by_host"].items(), key=lambda x: -x[1])[:20]),
    }
    with open(output_path, "w", encoding="utf-8") as f:
        json.dump(report, f, indent=2)


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python process.py <usb_events.csv>")
        sys.exit(1)

    csv_path = sys.argv[1]
    events = parse_usb_events(csv_path)
    analysis = analyze_usb_activity(events)

    out = os.path.join(os.path.dirname(csv_path) or ".", "usb_audit_report.json")
    generate_report(analysis, out)
    print(f"Report: {out}")
    print(f"Total events: {analysis['total_events']}, Blocked: {analysis['blocked_events']}")

Assets 1

template.mdtext/markdown · 0.6 KB
Keep exploring