{"id":"31f39e45-02e9-40ed-a0c7-dc140955133d","shortId":"XFcMw6","kind":"skill","title":"robotics-security","tagline":"Security hardening and best practices for robotic systems, covering SROS2 DDS security, network segmentation, secrets management, secure boot, and the physical-cyber safety intersection. Use this skill when securing ROS2 communications, configuring DDS encryption and access contr","description":"# Robotics Security Skill\n\n## When to Use This Skill\n- Enabling SROS2 encryption and access control on ROS2 topics/services\n- Generating keystores, certificates, and security policies for DDS\n- Hardening robot onboard computers (SSH, firewalls, minimal packages)\n- Setting up network segmentation between robot control/data/management planes\n- Managing secrets and credentials across a robot fleet\n- Securing Docker containers running ROS2 nodes\n- Designing e-stop and safety systems that survive cyber compromise\n- Auditing a robot system for security vulnerabilities\n- Implementing secure boot and firmware verification\n- Addressing IEC 62443 requirements for industrial robot deployments\n\n## The Robot Attack Surface\n\nRobots are unique: cyber vulnerabilities become **physical** threats.\n\n```\n  NETWORK                    MIDDLEWARE                   APPLICATION\n  ┌────────────────┐        ┌────────────────┐           ┌────────────────┐\n  │ Open DDS ports │───────▶│ Unauthenticated│──────────▶│ Hardcoded      │\n  │ (7400-7500)    │        │ /cmd_vel pub   │           │ credentials    │\n  │ Unsegmented LAN│        │ No msg signing │           │ Unvalidated cmd│\n  └────────────────┘        └────────────────┘           └────────────────┘\n  PHYSICAL                   FIRMWARE                     SUPPLY CHAIN\n  ┌────────────────┐        ┌────────────────┐           ┌────────────────┐\n  │ USB/debug ports│───────▶│ Unsigned       │──────────▶│ Compromised    │\n  │ Serial consoles│        │ firmware OTA   │           │ ROS packages   │\n  │ Exposed SBCs   │        │ No secure boot │           │ Unverified imgs│\n  └────────────────┘        └────────────────┘           └────────────────┘\n```\n\n| Vector | Impact |\n|--------|--------|\n| Unauthenticated `/cmd_vel` | Robot moves unexpectedly — injury/damage |\n| Sensor spoofing (`/scan`, `/camera/image`) | Robot collides, wrong decisions |\n| Open DDS multicast discovery | Full topic graph enumeration by passive listener |\n| USB/serial physical access | Root shell, firmware flash, data exfiltration |\n| Unsigned firmware update | Persistent backdoor in motor controllers |\n\n## SROS2: DDS Security\n\nSROS2 wraps DDS Security to provide authentication, encryption, and access control at the DDS layer.\n\n### Keystore Generation and Certificate Setup\n\n```bash\nexport ROS_SECURITY_KEYSTORE=~/sros2_keystore\nros2 security create_keystore ${ROS_SECURITY_KEYSTORE}\n\n# Generate per-node enclaves (use exact fully-qualified node names)\nros2 security create_enclave ${ROS_SECURITY_KEYSTORE} /my_robot/camera_driver\nros2 security create_enclave ${ROS_SECURITY_KEYSTORE} /my_robot/navigation\nros2 security create_enclave ${ROS_SECURITY_KEYSTORE} /my_robot/motor_controller\nros2 security create_enclave ${ROS_SECURITY_KEYSTORE} /my_robot/teleop\n\n# Result:\n# sros2_keystore/\n# ├── enclaves/my_robot/{camera_driver,navigation,...}/\n# │   ├── cert.pem, key.pem          # Node identity\n# │   ├── governance.p7s              # Signed governance\n# │   └── permissions.p7s             # Signed permissions\n# ├── public/ca.cert.pem              # CA certificate\n# └── private/ca.key.pem              # CA private key — PROTECT THIS\n```\n\n### Security Policy XML\n\n**Governance** — domain-wide security behavior:\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<dds xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n     xsi:noNamespaceSchemaLocation=\"omg_shared_ca_governance.xsd\">\n  <domain_access_rules>\n    <domain_rule>\n      <domains><id_range><min>0</min><max>230</max></id_range></domains>\n      <allow_unauthenticated_participants>false</allow_unauthenticated_participants>\n      <enable_join_access_control>true</enable_join_access_control>\n      <discovery_protection_kind>ENCRYPT</discovery_protection_kind>\n      <liveliness_protection_kind>ENCRYPT</liveliness_protection_kind>\n      <rtps_protection_kind>ENCRYPT</rtps_protection_kind>\n      <topic_access_rules>\n        <topic_rule>\n          <topic_expression>*</topic_expression>\n          <enable_discovery_protection>true</enable_discovery_protection>\n          <enable_read_access_control>true</enable_read_access_control>\n          <enable_write_access_control>true</enable_write_access_control>\n          <metadata_protection_kind>ENCRYPT</metadata_protection_kind>\n          <data_protection_kind>ENCRYPT</data_protection_kind>\n        </topic_rule>\n      </topic_access_rules>\n    </domain_rule>\n  </domain_access_rules>\n</dds>\n```\n\n**Permissions** — per-enclave publish/subscribe rules:\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<dds xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n     xsi:noNamespaceSchemaLocation=\"omg_shared_ca_permissions.xsd\">\n  <permissions>\n    <grant name=\"/my_robot/motor_controller\">\n      <subject_name>CN=/my_robot/motor_controller</subject_name>\n      <validity><not_before>2024-01-01T00:00:00</not_before>\n                <not_after>2026-01-01T00:00:00</not_after></validity>\n      <allow_rule>\n        <domains><id>0</id></domains>\n        <publish><topics><topic>rt/joint_states</topic></topics></publish>\n        <subscribe><topics><topic>rt/cmd_vel</topic></topics></subscribe>\n      </allow_rule>\n      <default>DENY</default>\n    </grant>\n    <grant name=\"/my_robot/teleop\">\n      <subject_name>CN=/my_robot/teleop</subject_name>\n      <validity><not_before>2024-01-01T00:00:00</not_before>\n                <not_after>2026-01-01T00:00:00</not_after></validity>\n      <allow_rule>\n        <domains><id>0</id></domains>\n        <publish><topics><topic>rt/cmd_vel</topic></topics></publish>\n        <subscribe><topics><topic>rt/joy</topic></topics></subscribe>\n      </allow_rule>\n      <default>DENY</default>\n    </grant>\n  </permissions>\n</dds>\n```\n\n### Enabling Security in Launch Files\n\n```python\nimport os\nfrom launch import LaunchDescription\nfrom launch_ros.actions import Node\n\ndef generate_launch_description():\n    security_env = {\n        'ROS_SECURITY_KEYSTORE': os.path.expanduser('~/sros2_keystore'),\n        'ROS_SECURITY_ENABLE': 'true',\n        'ROS_SECURITY_STRATEGY': 'Enforce',  # Enforce=reject unauth, Permissive=warn only\n    }\n    return LaunchDescription([\n        Node(package='my_robot_drivers', executable='motor_controller',\n             name='motor_controller', namespace='my_robot',\n             additional_env=security_env),\n        Node(package='my_robot_nav', executable='navigation',\n             name='navigation', namespace='my_robot',\n             additional_env=security_env),\n    ])\n```\n\nAlways use `Enforce` in production. `Permissive` logs violations but allows them — debugging aid only.\n\n### Per-Topic Access Control\n\nDesign with **least privilege**:\n\n| Node | Publishes | Subscribes | Rationale |\n|------|-----------|------------|-----------|\n| `motor_controller` | `/joint_states` | `/cmd_vel` | Driver acts on velocity only |\n| `navigation` | `/cmd_vel`, `/path` | `/scan`, `/odom`, `/map` | Nav reads sensors, writes commands |\n| `camera_driver` | `/camera/image_raw` | (none) | Pure source — no subscriptions |\n| `teleop` | `/cmd_vel` | `/joy` | Joystick passthrough — minimal surface |\n\nA compromised `camera_driver` **cannot** publish to `/cmd_vel` — permissions deny it at the DDS layer.\n\n## Network Hardening\n\n### Network Segmentation\n\n```\n┌───────────────────┬──────────────────┬────────────────────────┐\n│   CONTROL PLANE   │   DATA PLANE     │   MANAGEMENT PLANE     │\n│   VLAN 10         │   VLAN 20        │   VLAN 30              │\n│   10.10.10.0/24   │   10.10.20.0/24  │   10.10.30.0/24        │\n├───────────────────┼──────────────────┼────────────────────────┤\n│ /cmd_vel, /odom   │ /camera/image    │ SSH, Prometheus         │\n│ /joint_states     │ /pointcloud      │ Log collection          │\n│ /e_stop           │ /map, /rosbag    │ Fleet mgmt API          │\n├───────────────────┼──────────────────┼────────────────────────┤\n│ LOW LATENCY       │ HIGH BANDWIDTH   │ RESTRICTED ACCESS       │\n│ QoS: RELIABLE     │ QoS: BEST_EFFORT │ Jump host / VPN + 2FA  │\n└───────────────────┴──────────────────┴────────────────────────┘\n```\n\nManagement plane is **never** reachable from data plane. Control plane traffic never transits WiFi.\n\n### Firewall Rules for ROS2/DDS\n\n```bash\n#!/bin/bash\n# firewall_ros2.sh — adapt interface names to your hardware\niptables -F && iptables -X\n\n# Default: drop inbound, allow outbound\niptables -P INPUT DROP\niptables -P FORWARD DROP\niptables -P OUTPUT ACCEPT\n\niptables -A INPUT -i lo -j ACCEPT                                    # Loopback (intra-process DDS)\niptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT      # Existing connections\niptables -A INPUT -p udp --dport 7400:7500 -s 10.10.10.0/24 -j ACCEPT  # DDS discovery — control VLAN\niptables -A INPUT -p udp --dport 7500:7700 -s 10.10.10.0/24 -j ACCEPT  # DDS user traffic\niptables -A INPUT -p tcp --dport 22 -s 10.10.30.0/24 -j ACCEPT         # SSH — mgmt VLAN only\niptables -A INPUT -i wlan0 -d 239.255.0.0/16 -j DROP                   # Block multicast on WiFi\niptables -A INPUT -j LOG --log-prefix \"DROPPED: \" --log-level 4\niptables -A INPUT -j DROP\niptables-save > /etc/iptables/rules.v4\n```\n\n### VLAN Configuration for Robot Networks\n\n```yaml\n# /etc/netplan/01-robot-vlans.yaml\nnetwork:\n  version: 2\n  renderer: networkd\n  ethernets:\n    eth0: {dhcp4: false}\n  vlans:\n    vlan10:\n      id: 10\n      link: eth0\n      addresses: [10.10.10.5/24]\n    vlan20:\n      id: 20\n      link: eth0\n      addresses: [10.10.20.5/24]\n    vlan30:\n      id: 30\n      link: eth0\n      addresses: [10.10.30.5/24]\n      routes: [{to: default, via: 10.10.30.1}]\n```\n\n### Disabling DDS Multicast in Production\n\nMulticast auto-discovery exposes the full topic graph. Use unicast peer lists.\n\n```xml\n<!-- cyclonedds_secure.xml -->\n<CycloneDDS>\n  <Domain>\n    <General><AllowMulticast>false</AllowMulticast></General>\n    <Discovery>\n      <Peers>\n        <Peer address=\"10.10.10.1\"/>\n        <Peer address=\"10.10.10.2\"/>\n        <Peer address=\"10.10.10.3\"/>\n      </Peers>\n      <ParticipantIndex>auto</ParticipantIndex>\n    </Discovery>\n  </Domain>\n</CycloneDDS>\n```\n\n```bash\nexport CYCLONEDDS_URI=file:///etc/ros2/cyclonedds_secure.xml\nexport RMW_IMPLEMENTATION=rmw_cyclonedds_cpp\n```\n\nFastDDS equivalent — set `initialPeersList` with explicit unicast locators and omit multicast locators in the participant profile. Use `FASTRTPS_DEFAULT_PROFILES_FILE` env var to load.\n\n## SSH and Host Hardening\n\n### SSH Key-Only Auth, Disable Root Login\n\n```ini\n# /etc/ssh/sshd_config\nPort 2222\nPermitRootLogin no\nPasswordAuthentication no\nPubkeyAuthentication yes\nAuthorizedKeysFile .ssh/authorized_keys\nMaxAuthTries 3\nClientAliveInterval 300\nClientAliveCountMax 2\nAllowUsers robot-admin\nX11Forwarding no\nAllowTcpForwarding no\nPermitTunnel no\n```\n\n```bash\nsudo systemctl restart sshd\n# Per-robot key pair (on management workstation)\nssh-keygen -t ed25519 -f ~/.ssh/robot_$(hostname) -C \"admin@$(hostname)\"\nssh-copy-id -i ~/.ssh/robot_$(hostname).pub -p 2222 robot-admin@10.10.30.5\n```\n\n### fail2ban for Robot Computers\n\n```ini\n# /etc/fail2ban/jail.local\n[sshd]\nenabled = true\nport = 2222\nfilter = sshd\nlogpath = /var/log/auth.log\nmaxretry = 3\nbantime = 3600\nfindtime = 600\n```\n\n```bash\nsudo apt install fail2ban -y && sudo systemctl enable --now fail2ban\n```\n\n### Unattended Security Updates\n\n```bash\nsudo apt install unattended-upgrades -y\nsudo dpkg-reconfigure -plow unattended-upgrades\n# Key settings in /etc/apt/apt.conf.d/50unattended-upgrades:\n#   Allowed-Origins: \"${distro_id}:${distro_codename}-security\"\n#   Automatic-Reboot: \"false\"   # NEVER auto-reboot a running robot\n```\n\n### Minimal Installed Packages\n\n```bash\n# Remove unnecessary packages from robot computers\nsudo apt purge -y avahi-daemon cups snapd modemmanager bluetooth bluez\nsudo apt autoremove -y\n```\n\n## Secrets Management\n\n### No Hardcoded Credentials\n\n```python\n# BAD:\nclass FleetClient:\n    def __init__(self):\n        self.api_key = \"sk-live-abc123xyz789\"\n```\n\n```python\n# GOOD:\nimport os\nclass FleetClient:\n    def __init__(self):\n        self.api_key = os.environ['FLEET_API_KEY']\n```\n\n```yaml\n# BAD: credentials in params.yaml tracked by git\nfleet_manager:\n  ros__parameters:\n    aws_secret_key: \"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\"\n```\n\n```yaml\n# GOOD: reference environment variables\nfleet_manager:\n  ros__parameters:\n    aws_secret_key: \"$(env AWS_SECRET_KEY)\"\n```\n\n### Environment-Based Secrets for ROS2 Nodes\n\n```ini\n# /etc/systemd/system/robot-nav.service\n[Service]\nUser=robot\nGroup=robot\nEnvironmentFile=/etc/robot/secrets.env\nExecStart=/opt/ros/humble/bin/ros2 launch my_robot nav.launch.py\nRestart=always\n```\n\n```bash\n# /etc/robot/secrets.env\nFLEET_API_KEY=sk-live-actual-key-here\nROS_SECURITY_KEYSTORE=/opt/robot/sros2_keystore\n\n# Lock it down\nsudo chown root:robot /etc/robot/secrets.env\nsudo chmod 640 /etc/robot/secrets.env\n```\n\n### Certificate Rotation Patterns\n\n```bash\n#!/bin/bash\n# rotate_certs.sh — run via cron monthly\nset -euo pipefail\nKEYSTORE=\"/opt/robot/sros2_keystore\"\ncp -r \"${KEYSTORE}\" \"${KEYSTORE}_backup_$(date +%Y%m%d)\"\n\nfor enclave in motor_controller navigation camera_driver teleop; do\n    ros2 security create_enclave \"${KEYSTORE}\" \"/my_robot/${enclave}\"\ndone\nsudo systemctl restart robot-*.service\necho \"Certificates rotated at $(date)\"\n```\n\n```bash\n# /etc/cron.d/robot-cert-rotation\n0 3 1 * * root /opt/robot/scripts/rotate_certs.sh >> /var/log/cert-rotation.log 2>&1\n```\n\n### File Permissions for Keystores\n\n```bash\nsudo chown -R root:robot /opt/robot/sros2_keystore\nsudo find /opt/robot/sros2_keystore -type d -exec chmod 750 {} \\;\nsudo find /opt/robot/sros2_keystore -type f -exec chmod 640 {} \\;\n# CA private key — root only\nsudo chmod 600 /opt/robot/sros2_keystore/private/ca.key.pem\nsudo chown root:root /opt/robot/sros2_keystore/private/ca.key.pem\n```\n\n## Container Security\n\n### Non-Root Containers\n\n```dockerfile\nFROM ros:humble-ros-base AS runtime\nRUN apt-get update && apt-get install -y --no-install-recommends \\\n    ros-humble-nav2-bringup && rm -rf /var/lib/apt/lists/*\nRUN groupadd -g 1000 robot && useradd -u 1000 -g robot -m -s /bin/false robot\nCOPY --from=builder /opt/ros2_ws/install /opt/ros2_ws/install\nUSER robot:robot\nENTRYPOINT [\"/ros_entrypoint.sh\"]\nCMD [\"ros2\", \"launch\", \"my_robot\", \"nav.launch.py\"]\n```\n\n### Minimal Runtime Images\n\n```dockerfile\nFROM ros:humble-desktop AS builder\nWORKDIR /opt/ros2_ws\nCOPY src/ src/\nRUN . /opt/ros/humble/setup.sh && \\\n    colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release --merge-install\n\nFROM ros:humble-ros-core AS runtime\nCOPY --from=builder /opt/ros2_ws/install /opt/ros2_ws/install\n# Remove shell and package manager — prevents interactive exploitation\nRUN rm -f /bin/sh /bin/bash /bin/dash && apt-get purge -y --auto-remove apt\n```\n\n### Image Scanning and Signing\n\n```bash\ntrivy image --severity HIGH,CRITICAL my-robot/navigation:latest\ncosign sign --key cosign.key my-registry.io/my-robot/navigation:v1.2.3\ncosign verify --key cosign.pub my-registry.io/my-robot/navigation:v1.2.3 || exit 1\n```\n\n### Read-Only Root Filesystem\n\n```yaml\n# docker-compose.yml\nservices:\n  motor_controller:\n    image: my-robot/motor-controller:v1.0.0\n    user: \"1000:1000\"\n    read_only: true\n    tmpfs: [\"/tmp:size=64M\", \"/var/log/ros:size=32M\"]\n    volumes:\n      - type: bind\n        source: /opt/robot/sros2_keystore/enclaves/my_robot/motor_controller\n        target: /keystore\n        read_only: true\n    security_opt: [\"no-new-privileges:true\"]\n    cap_drop: [ALL]\n    environment:\n      ROS_SECURITY_KEYSTORE: /keystore\n      ROS_SECURITY_ENABLE: \"true\"\n      ROS_SECURITY_STRATEGY: Enforce\n```\n\n## Physical-Cyber Safety Intersection\n\nCyber attacks on robots cause **physical harm**. Standard IT security is necessary but not sufficient.\n\n### E-Stop Independence\n\nThe emergency stop **must** function with all software, network, and main compute completely dead.\n\n```\n  ┌──────────┐     HARDWIRED      ┌─────────────────┐\n  │ Physical  │ ─────────────────▶│ Safety Relay /   │──▶ Motor power cut\n  │ E-Stop    │  Direct circuit    │ Safety PLC       │   via contactor\n  │ Button    │  NO software       └─────────────────┘\n  └──────────┘\n  ┌──────────┐     OPTIONAL\n  │ Software  │ ───(notifies)───▶ Can trigger relay, but NOT sole path\n  │ E-Stop    │\n  └──────────┘\n  Main compute crash ──X──▶ Cannot prevent hardware e-stop\n  Network failure    ──X──▶ Cannot prevent hardware e-stop\n```\n\nDesign rules: hardwired circuit disconnects motor power; software triggers the relay but is never the only path; wireless e-stops use dedicated radio, not WiFi.\n\n### Safety Controller Isolation\n\n```\n┌──────────────────────────────┬───────────────────────────────┐\n│ MAIN COMPUTE (Jetson/x86)    │ SAFETY CONTROLLER (STM32/MCU) │\n│ Ubuntu + ROS2                │ Bare-metal firmware            │\n│ Nav, Perception, Planning    │                               │\n│             ──── CAN/UART ──▶│ Validates:                    │\n│                cmd_vel        │ - Max velocity                │\n│                               │ - Max acceleration            │\n│             ◀── joint_fb ────│ - Workspace limits            │\n│                               │ - Watchdog timeout            │\n│ If compromised, safety       │ Rejects out-of-bounds cmds    │\n│ controller STILL enforces    │ Runs on separate hardware     │\n│ physical limits.             │ Does NOT run ROS2 or Linux    │\n└──────────────────────────────┴───────────────────────────────┘\n```\n\n### Command Velocity Validation and Rate Limiting\n\nEnforce at the driver level — last line of defense before actuators:\n\n```python\n# velocity_safety_gate.py\nimport rclpy\nfrom rclpy.node import Node\nfrom geometry_msgs.msg import Twist\n\nclass VelocitySafetyGate(Node):\n    def __init__(self):\n        super().__init__('velocity_safety_gate')\n        self.declare_parameter('max_linear_vel', 1.0)   # m/s\n        self.declare_parameter('max_angular_vel', 2.0)   # rad/s\n        self.declare_parameter('max_linear_accel', 0.5)  # m/s^2\n        self.declare_parameter('cmd_timeout_sec', 0.5)\n        self.declare_parameter('max_cmd_rate_hz', 50.0)\n\n        self.max_lin = self.get_parameter('max_linear_vel').value\n        self.max_ang = self.get_parameter('max_angular_vel').value\n        self.max_acc = self.get_parameter('max_linear_accel').value\n        self.timeout = self.get_parameter('cmd_timeout_sec').value\n        self.min_period = 1.0 / self.get_parameter('max_cmd_rate_hz').value\n\n        self.last_cmd_time = self.get_clock().now()\n        self.last_linear = 0.0\n        self.last_pub_sec = 0.0\n\n        self.sub = self.create_subscription(Twist, 'cmd_vel_raw', self.on_cmd, 10)\n        self.pub = self.create_publisher(Twist, 'cmd_vel', 10)\n        self.create_timer(0.1, self.watchdog_check)\n\n    def on_cmd(self, msg: Twist):\n        now = self.get_clock().now()\n        now_sec = now.nanoseconds / 1e9\n        if (now_sec - self.last_pub_sec) < self.min_period:\n            return  # Rate limit exceeded — drop\n\n        msg.linear.x = max(-self.max_lin, min(self.max_lin, msg.linear.x))\n        msg.angular.z = max(-self.max_ang, min(self.max_ang, msg.angular.z))\n\n        dt = (now - self.last_cmd_time).nanoseconds / 1e9\n        if dt > 0:\n            accel = abs(msg.linear.x - self.last_linear) / dt\n            if accel > self.max_acc:\n                sign = 1.0 if msg.linear.x > self.last_linear else -1.0\n                msg.linear.x = self.last_linear + sign * self.max_acc * dt\n\n        self.pub.publish(msg)\n        self.last_cmd_time = now\n        self.last_linear = msg.linear.x\n        self.last_pub_sec = now_sec\n\n    def watchdog_check(self):\n        elapsed = (self.get_clock().now() - self.last_cmd_time).nanoseconds / 1e9\n        if elapsed > self.timeout:\n            self.pub.publish(Twist())  # No command → zero velocity\n```\n\n### Watchdog Independence from Application Software\n\n```python\n# Hardware watchdog — kernel resets system if not fed\nimport os\n\nclass HardwareWatchdog:\n    \"\"\"Uses /dev/watchdog. If not fed within timeout, kernel triggers reset.\"\"\"\n    def __init__(self):\n        self.fd = os.open('/dev/watchdog', os.O_WRONLY)  # Starts countdown\n    def feed(self):\n        os.write(self.fd, b'\\x00')  # Reset countdown\n    def close(self):\n        os.write(self.fd, b'V')     # Magic close — disarm gracefully\n        os.close(self.fd)\n```\n\n```bash\n# /etc/watchdog.conf\nwatchdog-device = /dev/watchdog\nwatchdog-timeout = 15\ninterval = 5\npidfile = /var/run/robot-safety-monitor.pid\nmax-load-1 = 24\n```\n\n## Secure Boot and Firmware\n\n### Read-Only Root Filesystem with Overlay\n\n```bash\n# /etc/fstab\n/dev/mmcblk0p2  /        ext4  ro,noatime,errors=remount-ro  0 1\ntmpfs           /tmp     tmpfs nosuid,nodev,size=128M         0 0\ntmpfs           /var/log tmpfs nosuid,nodev,size=128M         0 0\n/dev/mmcblk0p3  /data    ext4  rw,noatime,nosuid,nodev       0 2\n```\n\n```bash\n# Alternative: overlayroot — all writes go to tmpfs, lost on reboot\nsudo apt install overlayroot -y\n# /etc/overlayroot.conf → overlayroot=\"tmpfs:swap=1\"\n```\n\n### Signed Container Images\n\n```bash\n#!/bin/bash\nset -euo pipefail\nIMAGE=\"registry.myrobot.io/robot/navigation\"\nTAG=\"v$(cat VERSION)-$(git rev-parse --short HEAD)\"\ndocker build -t \"${IMAGE}:${TAG}\" -f Dockerfile.prod .\ntrivy image --exit-code 1 --severity CRITICAL \"${IMAGE}:${TAG}\"\ndocker push \"${IMAGE}:${TAG}\"\ncosign sign --key env://COSIGN_PRIVATE_KEY \"${IMAGE}:${TAG}\"\nsyft \"${IMAGE}:${TAG}\" -o spdx-json > sbom.json\ncosign attach sbom --sbom sbom.json \"${IMAGE}:${TAG}\"\n```\n\n### TPM-Based Disk Encryption\n\n```bash\n# LUKS + TPM2 for unattended encrypted boot\nsudo cryptsetup luksFormat /dev/mmcblk0p3\nsudo cryptsetup luksOpen /dev/mmcblk0p3 robot-data\nsudo systemd-cryptenroll /dev/mmcblk0p3 --tpm2-device=auto --tpm2-pcrs=0+7\n# Disk decrypts only on original hardware with unmodified firmware\n```\n\n### Firmware Update Verification\n\n```python\nfrom pathlib import Path\nfrom cryptography.hazmat.primitives.asymmetric import ec\nfrom cryptography.hazmat.primitives import hashes, serialization\nimport subprocess\n\ndef verify_and_flash(firmware: Path, signature: Path, pubkey_path: Path):\n    pubkey = serialization.load_pem_public_key(pubkey_path.read_bytes())\n    try:\n        pubkey.verify(signature.read_bytes(), firmware.read_bytes(),\n                      ec.ECDSA(hashes.SHA256()))\n    except Exception:\n        raise SecurityError(\"Firmware signature verification FAILED — aborting\")\n    subprocess.run(['flash-tool', '--write', str(firmware)], check=True)\n```\n\n## Audit and Monitoring\n\n### Security Logging for ROS2\n\n```python\n# topic_auditor.py — logs publications on sensitive topics\nimport rclpy, json, time\nfrom rclpy.node import Node\nfrom geometry_msgs.msg import Twist\n\nclass TopicAuditor(Node):\n    def __init__(self):\n        super().__init__('topic_auditor')\n        self.log = open('/var/log/ros2_audit.jsonl', 'a')\n        self.create_subscription(Twist, '/cmd_vel', self.audit_cmd_vel, 10)\n\n    def audit_cmd_vel(self, msg: Twist):\n        record = {'ts': time.time(), 'topic': '/cmd_vel',\n                  'lin_x': msg.linear.x, 'ang_z': msg.angular.z}\n        self.log.write(json.dumps(record) + '\\n')\n        self.log.flush()\n        if abs(msg.linear.x) > 0.8 or abs(msg.angular.z) > 1.5:\n            self.get_logger().warn(f'HIGH VEL: lin={msg.linear.x:.2f} ang={msg.angular.z:.2f}')\n```\n\n### Intrusion Detection on Command Topics\n\n```python\n# cmd_vel_anomaly_detector.py\nimport numpy as np\nfrom collections import deque\nimport rclpy\nfrom rclpy.node import Node\nfrom geometry_msgs.msg import Twist\n\nclass CmdVelAnomalyDetector(Node):\n    def __init__(self):\n        super().__init__('cmd_vel_anomaly_detector')\n        self.window = deque(maxlen=100)\n        self.alert_pub = self.create_publisher(Twist, '/security/cmd_vel_alert', 10)\n        self.create_subscription(Twist, '/cmd_vel', self.on_cmd, 10)\n\n    def on_cmd(self, msg: Twist):\n        self.window.append((msg.linear.x, msg.angular.z))\n        if len(self.window) < 20:\n            return\n        vels = np.array(list(self.window))\n        z_scores = np.abs((np.array([msg.linear.x, msg.angular.z]) - vels.mean(0)) / (vels.std(0) + 1e-6))\n        if np.any(z_scores > 3.0):\n            self.get_logger().error(f'ANOMALY: lin={msg.linear.x:.3f} ang={msg.angular.z:.3f} z={z_scores}')\n            self.alert_pub.publish(msg)\n```\n\n### auditd Rules for Robot Systems\n\n```bash\n# /etc/audit/rules.d/robot-security.rules\n-w /opt/robot/sros2_keystore/ -p rwxa -k robot_keystore\n-w /etc/robot/ -p wa -k robot_config\n-w /home/robot-admin/.ssh/ -p wa -k ssh_keys\n-w /opt/robot/firmware/ -p rwxa -k firmware_access\n-w /etc/systemd/system/robot- -p wa -k robot_services\n-a always,exit -F arch=b64 -F euid=0 -S execve -k root_commands\n-w /dev/bus/usb/ -p rwxa -k usb_access\n-w /etc/netplan/ -p wa -k network_config\n-w /etc/iptables/ -p wa -k firewall_config\n-w /usr/bin/docker -p x -k docker_exec\n```\n\n```bash\nsudo auditctl -R /etc/audit/rules.d/robot-security.rules\nsudo systemctl enable --now auditd\nsudo ausearch -k robot_keystore --start today\n```\n\n## Robotics Security Anti-Patterns\n\n### 1. Unauthenticated /cmd_vel\n\n**Problem:** Default ROS2 lets any DDS participant publish to `/cmd_vel`. One command from any machine on the LAN moves the robot.\n\n```bash\n# BAD: anyone on the network can do this\nros2 topic pub /cmd_vel geometry_msgs/Twist \"{linear: {x: 999.0}}\"\n```\n\n**Fix:** SROS2 with `Enforce`. Restrict `/cmd_vel` publish to authorized enclaves. Velocity safety gate as secondary check.\n\n```bash\n# GOOD: unauthorized publish rejected at DDS layer\nexport ROS_SECURITY_ENABLE=true\nexport ROS_SECURITY_STRATEGY=Enforce\n```\n\n### 2. Shared SSH Keys Across Robot Fleet\n\n**Problem:** One key compromised = entire fleet compromised.\n\n```bash\n# BAD: same key for all robots\nssh-copy-id -i ~/.ssh/fleet_key.pub robot@robot-001\nssh-copy-id -i ~/.ssh/fleet_key.pub robot@robot-002\n```\n\n**Fix:** Unique key per robot. Use SSH CA with short-lived certificates.\n\n```bash\n# GOOD: SSH CA issues 8-hour certs per session\nssh-keygen -s /etc/ssh/ca_key -I \"session-$(date +%s)\" -n robot-admin -V +8h ~/.ssh/id_ed25519.pub\n```\n\n### 3. Running All Nodes as Root\n\n**Problem:** Any compromised node = full root access to the system.\n\n```bash\n# BAD:\nsudo ros2 launch my_robot bringup.launch.py\n```\n\n**Fix:** Run as unprivileged user. Use udev rules for hardware access instead of root.\n\n```bash\n# GOOD:\nsudo -u robot ros2 launch my_robot bringup.launch.py\n# /etc/udev/rules.d/99-robot.rules:\n# SUBSYSTEM==\"tty\", ATTRS{idVendor}==\"0403\", MODE=\"0660\", GROUP=\"robot\"\n```\n\n### 4. No Network Segmentation\n\n**Problem:** All traffic on one flat network. Compromised IP camera reaches motor controller.\n\n**Fix:** VLAN segmentation with inter-VLAN firewall rules. See Network Hardening section.\n\n```bash\n# BAD: everything on 192.168.1.0/24\n\n# GOOD: VLAN 10 control (wired), VLAN 20 data, VLAN 30 mgmt (jump host)\n```\n\n### 5. Hardcoded Credentials in Launch Files\n\n**Problem:** Credentials in version control exposed to repo access, CI logs, Docker layers.\n\n```yaml\n# BAD: in params.yaml tracked by git\ncloud_connector:\n  ros__parameters:\n    aws_access_key: \"AKIAIOSFODNN7EXAMPLE\"\n```\n\n**Fix:** Environment variables from protected files. Scan repos with `gitleaks`.\n\n```bash\n# GOOD: secrets injected at runtime via systemd EnvironmentFile\ngitleaks detect --source . --verbose  # Pre-commit check\n```\n\n### 6. E-Stop Over Network\n\n**Problem:** Software e-stop over ROS2 as the **only** safety mechanism. Network down = no stop.\n\n```python\n# BAD: sole e-stop is a ROS2 topic subscriber\nself.create_subscription(Bool, '/e_stop', self.software_estop, 10)\n```\n\n**Fix:** Hardwired e-stop circuit. Software e-stop is an additional layer, never the sole path.\n\n### 7. No Certificate Rotation\n\n**Problem:** SROS2 certs generated once and never rotated. Compromised key = permanent access.\n\n**Fix:** Monthly automated rotation via cron. Explicit validity periods in permissions XML. Emergency rotation capability via fleet management.\n\n### 8. Disabling Security for Convenience\n\n**Problem:** SROS2 disabled in production because \"too hard\" or \"adds latency.\" Most common robotics security failure.\n\n```bash\n# BAD: \"temporary\" becomes permanent\nexport ROS_SECURITY_ENABLE=false\n```\n\n**Fix:** Security enabled in CI/CD from day one. Tests must pass with `Enforce`.\n\n```bash\n# GOOD: CI enforces security\nexport ROS_SECURITY_ENABLE=true\nexport ROS_SECURITY_STRATEGY=Enforce\nros2 launch my_robot test.launch.py  # Must pass with security on\n```\n\n## Robotics Security Checklist\n\n1. **SROS2 enabled with `Enforce` strategy** — all nodes use encrypted, authenticated DDS\n2. **Per-node enclaves with least-privilege permissions** — each node publishes/subscribes only to required topics\n3. **Network segmented into control/data/management VLANs** — firewall rules between zones\n4. **DDS multicast disabled** — unicast peer lists only, no auto-discovery on LAN\n5. **SSH hardened** — key-only auth, non-default port, fail2ban, no root login\n6. **No hardcoded credentials** — secrets from environment files with 640 permissions\n7. **Certificates rotated on schedule** — automated monthly rotation, explicit validity periods\n8. **Containers run as non-root** — USER directive, no-new-privileges, all capabilities dropped\n9. **E-stop is hardware-independent** — hardwired circuit works with all software/network down\n10. **Safety controller on separate hardware** — velocity/workspace limits enforced outside main compute\n11. **Command velocity validated at driver level** — clamping, rate limiting, watchdog to zero\n12. **auditd monitoring active** — keystore access, config changes, USB events, root commands logged\n13. **Firmware updates signature-verified** — no unsigned code on motor controllers or safety MCUs\n14. **Security tested in CI/CD** — SROS2 Enforce in integration tests, image scanning in pipeline","tags":["robotics","security","agent","skills","arpitg1304","agent-skills","ai-coding-assistant","claude-skills"],"capabilities":["skill","source-arpitg1304","skill-robotics-security","topic-agent-skills","topic-ai-coding-assistant","topic-claude-skills","topic-robotics"],"categories":["robotics-agent-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/arpitg1304/robotics-agent-skills/robotics-security","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add arpitg1304/robotics-agent-skills","source_repo":"https://github.com/arpitg1304/robotics-agent-skills","install_from":"skills.sh"}},"qualityScore":"0.544","qualityRationale":"deterministic score 0.54 from registry signals: · indexed on github topic:agent-skills · 189 github stars · SKILL.md body (29,839 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-02T18:54:20.988Z","embedding":null,"createdAt":"2026-04-18T22:05:36.010Z","updatedAt":"2026-05-02T18:54:20.988Z","lastSeenAt":"2026-05-02T18:54:20.988Z","tsv":"'+7':2181 '+8':2720 '-001':2673 '-002':2682 '-01':364,365,370,371,382,383,388,389 '-1.0':1884 '-7500':150 '/.ssh/fleet_key.pub':2670,2679 '/.ssh/id_ed25519.pub':2722 '/.ssh/robot_':922,932 '/16':731 '/24':568,570,572,685,702,717,784,792,800,2816 '/bin/bash':622,1161,1382,2083 '/bin/dash':1383 '/bin/false':1309 '/bin/sh':1381 '/camera/image':193,575 '/camera/image_raw':523 '/cmd_vel':151,185,504,511,530,543,573,2297,2313,2402,2570,2580,2604,2615 '/data':2050 '/dev/bus/usb':2519 '/dev/mmcblk0p2':2021 '/dev/mmcblk0p3':2049,2160,2164,2172 '/dev/watchdog':1949,1963,1994 '/e_stop':582,2927 '/etc/apt/apt.conf.d/50unattended-upgrades':995 '/etc/audit/rules.d/robot-security.rules':2468,2550 '/etc/cron.d/robot-cert-rotation':1210 '/etc/fail2ban/jail.local':946 '/etc/fstab':2020 '/etc/iptables':2533 '/etc/iptables/rules.v4':759 '/etc/netplan':2526 '/etc/netplan/01-robot-vlans.yaml':766 '/etc/overlayroot.conf':2074 '/etc/robot':2477 '/etc/robot/secrets.env':1121,1131,1152,1156 '/etc/ros2/cyclonedds_secure.xml':831 '/etc/ssh/ca_key':2710 '/etc/ssh/sshd_config':876 '/etc/systemd/system/robot-':2498 '/etc/systemd/system/robot-nav.service':1114 '/etc/udev/rules.d/99-robot.rules':2771 '/etc/watchdog.conf':1990 '/home/robot-admin/.ssh':2484 '/joint_states':503,578 '/joy':531 '/keystore':1459,1477 '/map':515,583 '/motor-controller':1438 '/my-robot/navigation:v1.2.3':1414,1421 '/my_robot':1196 '/my_robot/camera_driver':281 '/my_robot/motor_controller':297,362 '/my_robot/navigation':289 '/my_robot/teleop':305,380 '/navigation':1406 '/odom':514,574 '/opt/robot/firmware':2491 '/opt/robot/scripts/rotate_certs.sh':1215 '/opt/robot/sros2_keystore':1144,1171,1229,1232,1240,2470 '/opt/robot/sros2_keystore/enclaves/my_robot/motor_controller':1457 '/opt/robot/sros2_keystore/private/ca.key.pem':1254,1259 '/opt/ros/humble/bin/ros2':1123 '/opt/ros/humble/setup.sh':1344 '/opt/ros2_ws':1339 '/opt/ros2_ws/install':1314,1315,1368,1369 '/path':512 '/pointcloud':579 '/robot/navigation':2090 '/ros_entrypoint.sh':1320 '/rosbag':584 '/scan':192,513 '/security/cmd_vel_alert':2397 '/sros2_keystore':254,423 '/tmp':1447,2032 '/usr/bin/docker':2540 '/var/lib/apt/lists':1296 '/var/log':2041 '/var/log/auth.log':955 '/var/log/cert-rotation.log':1216 '/var/log/ros':1450 '/var/log/ros2_audit.jsonl':2292 '/var/run/robot-safety-monitor.pid':2002 '0':342,375,393,1211,1864,2029,2038,2039,2047,2048,2056,2180,2435,2437,2512 '0.0':1781,1785 '0.1':1805 '0.5':1716,1724 '0.8':2331 '00':367,368,373,374,385,386,391,392 '0403':2776 '0660':2778 '1':1213,1218,1423,2006,2030,2078,2113,2568,3055 '1.0':1702,1765,1877 '1.5':2336 '10':562,779,1795,1802,2301,2398,2405,2819,2930,3176 '10.10.10.0':567,684,701 '10.10.10.5':783 '10.10.20.0':569 '10.10.20.5':791 '10.10.30.0':571,716 '10.10.30.1':805 '10.10.30.5':799,940 '100':2391 '1000':1300,1304,1441,1442 '11':3188 '12':3201 '128m':2037,2046 '13':3214 '14':3229 '15':1998 '192.168.1.0':2815 '1e-6':2438 '1e9':1821,1861,1920 '2':769,892,1217,1718,2057,2644,3067 '2.0':1709 '20':564,787,2420,2823 '2024':363,381 '2026':369,387 '22':714 '2222':878,936,951 '230':343 '239.255.0.0':730 '24':2007 '2f':2346,2350 '2fa':602 '3':888,957,1212,2723,3084 '3.0':2443 '30':566,795,2826 '300':890 '32m':1452 '3600':959 '3f':2452,2456 '4':750,2781,3094 '5':2000,2830,3108 '50.0':1731 '6':2891,3123 '600':961,1253 '62443':123 '640':1155,1245,3132 '64m':1449 '7':2949,3134 '7400':149,681 '750':1237 '7500':682,698 '7700':699 '8':2701,2983,3145 '9':3161 '999.0':2609 'ab':1866,2328,2333 'abc123xyz789':1058 'abort':2244 'acc':1749,1875,1891 'accel':1715,1754,1865,1873 'acceler':1626 'accept':650,657,672,687,704,719 'access':40,54,211,238,491,593,2496,2524,2735,2757,2844,2861,2964,3206 'across':87,2648 'act':506 'activ':3204 'actual':1138 'actuat':1673 'adapt':624 'add':2997 'addit':454,470,2943 'address':121,782,790,798 'admin':896,925,939,2718 'aid':486 'akiaiosfodnn7example':2863 'allow':483,637,997 'allowed-origin':996 'allowtcpforward':899 'allowus':893 'altern':2059 'alway':474,1129,2505 'ang':1741,1849,1852,2318,2347,2453 'angular':1707,1745 'anomali':2386,2448 'anti':2566 'anti-pattern':2565 'anyon':2594 'api':587,1072,1133 'applic':143,1933 'apt':964,978,1026,1038,1277,1281,1385,1392,2070 'apt-get':1276,1280,1384 'arch':2508 'arg':1349 'attach':2139 'attack':131,1492 'attr':2774 'audit':108,2254,2303 'auditctl':2548 'auditd':2462,2555,3202 'auditor':2289 'ausearch':2557 'auth':871,3114 'authent':235,3065 'author':2618 'authorizedkeysfil':885 'auto':813,826,1010,1390,2176,3104 'auto-discoveri':812,3103 'auto-reboot':1009 'auto-remov':1389 'autom':2967,3139 'automat':1005 'automatic-reboot':1004 'autoremov':1039 'avahi':1030 'avahi-daemon':1029 'aw':1086,1099,1103,2860 'b':1972,1981 'b64':2509 'backdoor':222 'backup':1176 'bad':1047,1075,2593,2659,2740,2812,2850,2914,3005 'bandwidth':591 'bantim':958 'bare':1613 'bare-met':1612 'base':1108,1272,2147 'bash':249,621,827,903,962,976,1018,1130,1160,1209,1223,1397,1989,2019,2058,2082,2150,2467,2546,2592,2626,2658,2696,2739,2761,2811,2874,3004,3027 'becom':138,3007 'behavior':340 'best':7,597 'bind':1455 'block':734 'bluetooth':1035 'bluez':1036 'bool':2926 'boot':21,117,179,2009,2156 'bound':1640 'bringup':1293 'bringup.launch.py':2746,2770 'build':1346,1351,2102 'builder':1313,1337,1367 'button':1540 'byte':2227,2231,2233 'c':924 'ca':324,327,1246,2690,2699 'camera':310,521,538,1187,2794 'can/uart':1619 'cannot':540,1560,1569 'cap':1470 'capabl':2979,3159 'cat':2093 'caus':1495 'cert':2703,2955 'cert.pem':313 'certif':61,247,325,1157,1205,2695,2951,3135 'chain':164 'chang':3208 'check':1807,1910,2252,2625,2890 'checklist':3054 'chmod':1154,1236,1244,1252 'chown':1149,1225,1256 'ci':2845,3029 'ci/cd':3018,3233 'circuit':1535,1578,2936,3170 'clamp':3195 'class':1048,1063,1686,1946,2280,2376 'clientalivecountmax':891 'clientaliveinterv':889 'clock':1777,1816,1914 'close':1977,1984 'cloud':2856 'cmake':1348 'cmake-arg':1347 'cmd':160,1321,1621,1721,1728,1759,1769,1774,1790,1794,1800,1810,1858,1896,1917,2299,2304,2384,2404,2408 'cmd_vel_anomaly_detector.py':2357 'cmds':1641 'cmdvelanomalydetector':2377 'cn':361,379 'code':2112,3222 'codenam':1002 'colcon':1345 'collect':581,2363 'collid':195 'command':520,1657,1927,2354,2517,2582,3189,3212 'commit':2889 'common':3000 'communic':35 'complet':1522 'compromis':107,168,537,1634,2654,2657,2731,2792,2961 'comput':70,944,1024,1521,1557,1605,3187 'config':2482,2531,2538,3207 'configur':36,761 'connect':674 'connector':2857 'consol':170 'contactor':1539 'contain':93,1260,1265,2080,3146 'contr':41 'control':55,225,239,447,450,492,502,555,611,690,1185,1433,1602,1608,1642,2797,2820,2840,3178,3225 'control/data/management':81,3088 'conveni':2987 'copi':929,1311,1340,1365,2667,2676 'core':1362 'cosign':1408,1415,2122,2125,2138 'cosign.key':1411 'cosign.pub':1418 'countdown':1966,1975 'cover':12 'cp':1172 'cpp':837 'crash':1558 'creat':257,276,284,292,300,1193 'credenti':86,153,1045,1076,2832,2837,3126 'critic':1402,2115 'cron':1165,2970 'cryptenrol':2171 'cryptography.hazmat.primitives':2204 'cryptography.hazmat.primitives.asymmetric':2200 'cryptsetup':2158,2162 'cup':1032 'cut':1530 'cyber':26,106,136,1488,1491 'cyclonedd':829,836 'd':729,1180,1234 'daemon':1031 'data':216,557,609,2167,2824 'date':1177,1208,2713 'day':3020 'dcmake':1350 'dds':14,37,66,145,199,227,231,242,549,662,688,705,807,2576,2632,3066,3095 'dead':1523 'debug':485 'decis':197 'decrypt':2183 'dedic':1597 'def':413,1050,1065,1689,1808,1908,1958,1967,1976,2210,2283,2302,2379,2406 'default':634,803,856,2572,3117 'defens':1671 'deni':378,396,545 'deploy':128 'dequ':2365,2389 'descript':416 'design':97,493,1575 'desktop':1335 'detect':2352,2884 'detector':2387 'devic':1993,2175 'dhcp4':774 'direct':1534,3153 'disabl':806,872,2984,2990,3097 'disarm':1985 'disconnect':1579 'discoveri':201,689,814,3105 'disk':2148,2182 'distro':999,1001 'docker':92,2101,2118,2544,2847 'docker-compose.yml':1430 'dockerfil':1266,1330 'dockerfile.prod':2107 'domain':337 'domain-wid':336 'done':1198 'dpkg':986 'dpkg-reconfigur':985 'dport':680,697,713 'driver':311,444,505,522,539,1188,1666,3193 'drop':635,642,646,733,746,755,1471,1834,3160 'dt':1855,1863,1871,1892 'e':99,1507,1532,1554,1564,1573,1594,2893,2900,2917,2934,2939,3163 'e-stop':98,1506,1531,1553,1563,1572,1593,2892,2899,2916,2933,2938,3162 'ec':2202 'ec.ecdsa':2234 'echo':1204 'ed25519':920 'effort':598 'elaps':1912,1922 'els':1883 'emerg':1511,2977 'enabl':50,397,426,948,970,1480,2553,2637,3012,3016,3035,3057 'enclav':266,277,285,293,301,357,1182,1194,1197,2619,3071 'enclaves/my_robot':309 'encrypt':38,52,236,346,347,348,352,353,2149,2155,3064 'enforc':431,432,476,1485,1644,1663,2613,2643,3026,3030,3041,3059,3184,3235 'entir':2655 'entrypoint':1319 'enumer':205 'env':418,455,457,471,473,859,1102 'environ':1093,1107,1473,2865,3129 'environment-bas':1106 'environmentfil':1120,2882 'equival':839 'error':2025,2446 'establish':669 'estop':2929 'eth0':773,781,789,797 'ethernet':772 'euid':2511 'euo':1168,2085 'event':3210 'everyth':2813 'exact':268 'exceed':1833 'except':2236,2237 'exec':1235,1243,2545 'execstart':1122 'execut':445,463 'execv':2514 'exfiltr':217 'exist':673 'exit':1422,2111,2506 'exit-cod':2110 'explicit':843,2971,3142 'exploit':1377 'export':250,828,832,2634,2639,3009,3032,3037 'expos':175,815,2841 'ext4':2022,2051 'f':631,921,1242,1380,2106,2340,2447,2507,2510 'fail':2243 'fail2ban':941,966,972,3119 'failur':1567,3003 'fals':344,775,825,1007,3013 'fastdd':838 'fastrtp':855 'fb':1628 'fed':1943,1952 'feed':1968 'file':401,858,1219,2835,2869,3130 'filesystem':1428,2016 'filter':952 'find':1231,1239 'findtim':960 'firewal':72,617,2537,2805,3090 'firewall_ros2.sh':623 'firmwar':119,162,171,214,219,1615,2011,2190,2191,2214,2240,2251,2495,3215 'firmware.read':2232 'fix':2610,2683,2747,2798,2864,2931,2965,3014 'flash':215,2213,2247 'flash-tool':2246 'flat':2790 'fleet':90,585,1071,1082,1095,1132,2650,2656,2981 'fleetclient':1049,1064 'forward':645 'full':202,817,2733 'fulli':270 'fully-qualifi':269 'function':1514 'g':1299,1305 'gate':1696,2622 'generat':59,245,262,414,2956 'geometri':2605 'geometry_msgs.msg':1683,2277,2373 'get':1278,1282,1386 'git':1081,2095,2855 'gitleak':2873,2883 'go':2063 'good':1060,1091,2627,2697,2762,2817,2875,3028 'govern':319,335 'governance.p7s':317 'grace':1986 'graph':204,819 'group':1118,2779 'groupadd':1298 'h':2721 'hard':2995 'hardcod':148,1044,2831,3125 'harden':5,67,552,866,2809,3110 'hardwar':629,1562,1571,1648,1936,2187,2756,3167,3181 'hardware-independ':3166 'hardwarewatchdog':1947 'hardwir':1524,1577,2932,3169 'harm':1497 'hash':2206 'hashes.sha256':2235 'head':2100 'high':590,1401,2341 'host':600,865,2829 'hostnam':923,926,933 'hour':2702 'humbl':1270,1291,1334,1360 'humble-desktop':1333 'humble-ros-bas':1269 'humble-ros-cor':1359 'hz':1730,1771 'id':778,786,794,930,1000,2668,2677 'ident':316 'idvendor':2775 'iec':122 'imag':1329,1393,1399,1434,2081,2087,2104,2109,2116,2120,2128,2131,2143,3239 'img':181 'impact':183 'implement':115,834 'import':403,407,411,1061,1676,1680,1684,1944,2197,2201,2205,2208,2268,2274,2278,2358,2364,2366,2370,2374 'inbound':636 'independ':1509,1931,3168 'industri':126 'ini':875,945,1113 'init':1051,1066,1690,1693,1959,2284,2287,2380,2383 'initialpeerslist':841 'inject':2877 'injury/damage':189 'input':641,653,665,677,694,710,726,740,753 'instal':965,979,1016,1283,1287,1356,2071 'instead':2758 'integr':3237 'inter':2803 'inter-vlan':2802 'interact':1376 'interfac':625 'intersect':28,1490 'interv':1999 'intra':660 'intra-process':659 'intrus':2351 'ip':2793 'iptabl':630,632,639,643,647,651,663,675,692,708,724,738,751,757 'iptables-sav':756 'isol':1603 'issu':2700 'j':656,671,686,703,718,732,741,754 'jetson/x86':1606 'joint':1627 'joystick':532 'json':2136,2270 'json.dumps':2323 'jump':599,2828 'k':2473,2480,2487,2494,2501,2515,2522,2529,2536,2543,2558 'kernel':1938,1955 'key':329,869,911,992,1054,1069,1073,1088,1101,1105,1134,1139,1248,1410,1417,2124,2127,2225,2489,2647,2653,2661,2685,2862,2962,3112 'key-on':868,3111 'key.pem':314 'keygen':918,2708 'keystor':60,244,253,258,261,280,288,296,304,308,421,1143,1170,1174,1175,1195,1222,1476,2475,2560,3205 'lan':155,2588,3107 'last':1668 'latenc':589,2998 'latest':1407 'launch':400,406,415,1124,1323,2743,2767,2834,3043 'launch_ros.actions':410 'launchdescript':408,439 'layer':243,550,2633,2848,2944 'least':495,3074 'least-privileg':3073 'len':2418 'let':2574 'level':749,1667,3194 'limit':1630,1650,1662,1832,3183,3197 'lin':1733,1839,1842,2314,2343,2449 'line':1669 'linear':1700,1714,1737,1753,1780,1870,1882,1888,1900,2607 'link':780,788,796 'linux':1656 'list':823,2424,3100 'listen':208 'live':1057,1137,2694 'lo':655 'load':862,2005 'locat':845,849 'lock':1145 'log':480,580,742,744,748,2258,2263,2846,3213 'log-level':747 'log-prefix':743 'logger':2338,2445 'login':874,3122 'logpath':954 'loopback':658 'lost':2066 'low':588 'luk':2151 'luksformat':2159 'luksopen':2163 'm':666,1179,1307 'm/s':1703,1717 'machin':2585 'magic':1983 'main':1520,1556,1604,3186 'manag':19,83,559,603,914,1042,1083,1096,1374,2982 'max':1623,1625,1699,1706,1713,1727,1736,1744,1752,1768,1837,1847,2004 'max-load':2003 'maxauthtri':887 'maxlen':2390 'maxretri':956 'mcus':3228 'mechan':2908 'merg':1355 'merge-instal':1354 'metal':1614 'mgmt':586,721,2827 'middlewar':142 'min':1840,1850 'minim':73,534,1015,1327 'mode':2777 'modemmanag':1034 'monitor':2256,3203 'month':1166,2966,3140 'motor':224,446,449,501,1184,1432,1528,1580,2796,3224 'move':187,2589 'msg':157,1812,1894,2307,2410,2461 'msg.angular':1845,1853,2320,2334,2348,2415,2432,2454 'msg.linear':1835,1843,1867,1879,1885,1901,2316,2329,2344,2413,2430,2450 'msgs/twist':2606 'multicast':200,735,808,811,848,3096 'must':1513,3023,3047 'my-registry.io':1413,1420 'my-registry.io/my-robot/navigation:v1.2.3':1412,1419 'my-robot':1403,1435 'n':2325,2715 'name':273,448,465,626 'namespac':451,467 'nanosecond':1860,1919 'nav':462,516,1616 'nav.launch.py':1127,1326 'nav2':1292 'navig':312,464,466,510,1186 'necessari':1502 'network':16,77,141,551,553,764,767,1518,1566,2530,2597,2783,2791,2808,2896,2909,3085 'networkd':771 'never':606,614,1008,1588,2945,2959 'new':1467,3156 'no-install-recommend':1285 'no-new-privileg':1465,3154 'noatim':2024,2053 'node':96,265,272,315,412,440,458,497,1112,1681,1688,2275,2282,2371,2378,2726,2732,3062,3070,3078 'nodev':2035,2044,2055 'non':1263,3116,3150 'non-default':3115 'non-root':1262,3149 'none':524 'nosuid':2034,2043,2054 'notifi':1545 'now.nanoseconds':1820 'np':2361 'np.abs':2428 'np.any':2440 'np.array':2423,2429 'numpi':2359 'o':2133 'omit':847 'onboard':69 'one':2581,2652,2789,3021 'open':144,198,2291 'opt':1464 'option':1543 'origin':998,2186 'os':404,1062,1945 'os.close':1987 'os.environ':1070 'os.o_wronly':1964 'os.open':1962 'os.path.expanduser':422 'os.write':1970,1979 'ota':172 'out-of-bound':1637 'outbound':638 'output':649 'outsid':3185 'overlay':2018 'overlayroot':2060,2072,2075 'p':640,644,648,678,695,711,935,2471,2478,2485,2492,2499,2520,2527,2534,2541 'packag':74,174,441,459,1017,1021,1373 'pair':912 'paramet':1085,1098,1698,1705,1712,1720,1726,1735,1743,1751,1758,1767,2859 'params.yaml':1078,2852 'pars':2098 'particip':852,2577 'pass':3024,3048 'passiv':207 'passthrough':533 'passwordauthent':881 'path':1552,1591,2198,2215,2217,2219,2220,2948 'pathlib':2196 'pattern':1159,2567 'pcrs':2179 'peer':822,3099 'pem':2223 'per':264,356,489,909,2686,2704,3069 'per-enclav':355 'per-nod':263,3068 'per-robot':908 'per-top':488 'percept':1617 'period':1764,1829,2973,3144 'perman':2963,3008 'permiss':322,354,435,479,544,1220,2975,3076,3133 'permissions.p7s':320 'permitrootlogin':879 'permittunnel':901 'persist':221 'physic':25,139,161,210,1487,1496,1525,1649 'physical-cyb':24,1486 'pidfil':2001 'pipefail':1169,2086 'pipelin':3242 'plan':1618 'plane':82,556,558,560,604,610,612 'plc':1537 'plow':988 'polici':64,333 'port':146,166,877,950,3118 'power':1529,1581 'practic':8 'pre':2888 'pre-commit':2887 'prefix':745 'prevent':1375,1561,1570 'privat':328,1247,2126 'private/ca.key.pem':326 'privileg':496,1468,3075,3157 'problem':2571,2651,2729,2785,2836,2897,2953,2988 'process':661 'product':478,810,2992 'profil':853,857 'prometheus':577 'protect':330,2868 'provid':234 'pub':152,934,1783,1826,1904,2393,2603 'pubkey':2218,2221 'pubkey.verify':2229 'pubkey_path.read':2226 'pubkeyauthent':883 'public':2224,2264 'public/ca.cert.pem':323 'publish':498,541,1798,2395,2578,2616,2629 'publish/subscribe':358 'publishes/subscribes':3079 'pure':525 'purg':1027,1387 'push':2119 'python':402,1046,1059,1674,1935,2194,2261,2356,2913 'qos':594,596 'qualifi':271 'r':1173,1226,2549 'rad/s':1710 'radio':1598 'rais':2238 'rate':1661,1729,1770,1831,3196 'rational':500 'raw':1792 'rclpi':1677,2269,2367 'rclpy.node':1679,2273,2369 'reach':2795 'reachabl':607 'read':517,1425,1443,1460,2013 'read-on':1424,2012 'reboot':1006,1011,2068 'recommend':1288 'reconfigur':987 'record':2309,2324 'refer':1092 'registry.myrobot.io':2089 'registry.myrobot.io/robot/navigation':2088 'reject':433,1636,2630 'relat':670 'relay':1527,1548,1585 'releas':1353 'reliabl':595 'remount':2027 'remount-ro':2026 'remov':1019,1370,1391 'render':770 'repo':2843,2871 'requir':124,3082 'reset':1939,1957,1974 'restart':906,1128,1201 'restrict':592,2614 'result':306 'return':438,1830,2421 'rev':2097 'rev-pars':2096 'rf':1295 'rm':1294,1379 'rmw':833,835 'ro':2023,2028 'robot':2,10,42,68,80,89,110,127,130,133,186,194,443,453,461,469,763,895,910,938,943,1014,1023,1117,1119,1126,1151,1202,1228,1301,1306,1310,1317,1318,1325,1405,1437,1494,2166,2465,2474,2481,2502,2559,2563,2591,2649,2664,2671,2672,2680,2681,2687,2717,2745,2765,2769,2780,3001,3045,3052 'robot-admin':894,937,2716 'robot-data':2165 'robotics-secur':1 'root':212,873,1150,1214,1227,1249,1257,1258,1264,1427,2015,2516,2728,2734,2760,3121,3151,3211 'ros':173,251,259,278,286,294,302,419,424,428,1084,1097,1141,1268,1271,1290,1332,1358,1361,1474,1478,1482,2635,2640,2858,3010,3033,3038 'ros-humble-nav2-bringup':1289 'ros2':34,57,95,255,274,282,290,298,1111,1191,1322,1611,1654,2260,2573,2601,2742,2766,2903,2921,3042 'ros2/dds':620 'rotat':1158,1206,2952,2960,2968,2978,3136,3141 'rotate_certs.sh':1162 'rout':801 'rt/cmd_vel':377,394 'rt/joint_states':376 'rt/joy':395 'rule':359,618,1576,2463,2754,2806,3091 'run':94,1013,1163,1275,1297,1343,1378,1645,1653,2724,2748,3147 'runtim':1274,1328,1364,2879 'rw':2052 'rwxa':2472,2493,2521 'safeti':27,102,1489,1526,1536,1601,1607,1635,1695,2621,2907,3177,3227 'save':758 'sbcs':176 'sbom':2140,2141 'sbom.json':2137,2142 'scan':1394,2870,3240 'schedul':3138 'score':2427,2442,2459 'sec':1723,1761,1784,1819,1824,1827,1905,1907 'secondari':2624 'secret':18,84,1041,1087,1100,1104,1109,2876,3127 'section':2810 'secur':3,4,15,20,33,43,63,91,113,116,178,228,232,252,256,260,275,279,283,287,291,295,299,303,332,339,398,417,420,425,429,456,472,974,1003,1142,1192,1261,1463,1475,1479,1483,1500,2008,2257,2564,2636,2641,2985,3002,3011,3015,3031,3034,3039,3050,3053,3230 'securityerror':2239 'see':2807 'segment':17,78,554,2784,2800,3086 'self':1052,1067,1691,1811,1911,1960,1969,1978,2285,2306,2381,2409 'self.alert':2392 'self.alert_pub.publish':2460 'self.api':1053,1068 'self.audit':2298 'self.create':1787,1797,1803,2294,2394,2399,2924 'self.declare':1697,1704,1711,1719,1725 'self.fd':1961,1971,1980,1988 'self.get':1734,1742,1750,1757,1766,1776,1815,1913,2337,2444 'self.last':1773,1779,1782,1825,1857,1869,1881,1887,1895,1899,1903,1916 'self.log':2290 'self.log.flush':2326 'self.log.write':2322 'self.max':1732,1740,1748,1838,1841,1848,1851,1874,1890 'self.min':1763,1828 'self.on':1793,2403 'self.pub':1796 'self.pub.publish':1893,1924 'self.software':2928 'self.sub':1786 'self.timeout':1756,1923 'self.watchdog':1806 'self.window':2388,2419,2425 'self.window.append':2412 'sensit':2266 'sensor':190,518 'separ':1647,3180 'serial':169,2207 'serialization.load':2222 'servic':1115,1203,1431,2503 'session':2705,2712 'set':75,840,993,1167,2084 'setup':248 'sever':1400,2114 'share':2645 'shell':213,1371 'short':2099,2693 'short-liv':2692 'sign':158,318,321,1396,1409,1876,1889,2079,2123 'signatur':2216,2241,3218 'signature-verifi':3217 'signature.read':2230 'size':1448,1451,2036,2045 'sk':1056,1136 'sk-live-abc123xyz789':1055 'sk-live-actual-key-her':1135 'skill':31,44,49 'skill-robotics-security' 'snapd':1033 'softwar':1517,1542,1544,1582,1934,2898,2937 'software/network':3174 'sole':1551,2915,2947 'sourc':526,1456,2885 'source-arpitg1304' 'spdx':2135 'spdx-json':2134 'spoof':191 'src':1341,1342 'sros2':13,51,226,229,307,2611,2954,2989,3056,3234 'ssh':71,576,720,863,867,917,928,2488,2646,2666,2675,2689,2698,2707,3109 'ssh-copy-id':927,2665,2674 'ssh-keygen':916,2706 'ssh/authorized_keys':886 'sshd':907,947,953 'standard':1498 'start':1965,2561 'state':667,668 'still':1643 'stm32/mcu':1609 'stop':100,1508,1512,1533,1555,1565,1574,1595,2894,2901,2912,2918,2935,2940,3164 'str':2250 'strategi':430,1484,2642,3040,3060 'subprocess':2209 'subprocess.run':2245 'subscrib':499,2923 'subscript':528,1788,2295,2400,2925 'subsystem':2772 'sudo':904,963,968,977,984,1025,1037,1148,1153,1199,1224,1230,1238,1251,1255,2069,2157,2161,2168,2547,2551,2556,2741,2763 'suffici':1505 'super':1692,2286,2382 'suppli':163 'surfac':132,535 'surviv':105 'swap':2077 'syft':2130 'system':11,103,111,1940,2466,2738 'systemctl':905,969,1200,2552 'systemd':2170,2881 'systemd-cryptenrol':2169 't00':366,372,384,390 'tag':2091,2105,2117,2121,2129,2132,2144 'target':1458 'tcp':712 'teleop':529,1189 'temporari':3006 'test':3022,3231,3238 'test.launch.py':3046 'threat':140 'time':1775,1859,1897,1918,2271 'time.time':2311 'timeout':1632,1722,1760,1954,1997 'timer':1804 'tmpfs':1446,2031,2033,2040,2042,2065,2076 'today':2562 'tool':2248 'topic':203,490,818,2267,2288,2312,2355,2602,2922,3083 'topic-agent-skills' 'topic-ai-coding-assistant' 'topic-claude-skills' 'topic-robotics' 'topic_auditor.py':2262 'topicauditor':2281 'topics/services':58 'tpm':2146 'tpm-base':2145 'tpm2':2152,2174,2178 'tpm2-device':2173 'tpm2-pcrs':2177 'track':1079,2853 'traffic':613,707,2787 'transit':615 'tri':2228 'trigger':1547,1583,1956 'trivi':1398,2108 'true':345,349,350,351,427,949,1445,1462,1469,1481,2253,2638,3036 'ts':2310 'tti':2773 'twist':1685,1789,1799,1813,1925,2279,2296,2308,2375,2396,2401,2411 'type':1233,1241,1352,1454 'u':1303,2764 'ubuntu':1610 'udev':2753 'udp':679,696 'unattend':973,981,990,2154 'unattended-upgrad':980,989 'unauth':434 'unauthent':147,184,2569 'unauthor':2628 'unexpect':188 'unicast':821,844,3098 'uniqu':135,2684 'unmodifi':2189 'unnecessari':1020 'unprivileg':2750 'unseg':154 'unsign':167,218,3221 'unvalid':159 'unverifi':180 'updat':220,975,1279,2192,3216 'upgrad':982,991 'uri':830 'usb':2523,3209 'usb/debug':165 'usb/serial':209 'use':29,47,267,475,820,854,1596,1948,2688,2752,3063 'user':706,1116,1316,1440,2751,3152 'useradd':1302 'v':1982,2092,2719 'v1.0.0':1439 'valid':1620,1659,2972,3143,3191 'valu':1739,1747,1755,1762,1772 'var':860 'variabl':1094,2866 'vector':182 'vel':1622,1701,1708,1738,1746,1791,1801,2300,2305,2342,2385,2422 'veloc':508,1624,1658,1694,1929,2620,3190 'velocity/workspace':3182 'velocity_safety_gate.py':1675 'velocitysafetyg':1687 'vels.mean':2434 'vels.std':2436 'verbos':2886 'verif':120,2193,2242 'verifi':1416,2211,3219 'version':768,2094,2839 'via':804,1164,1538,2880,2969,2980 'violat':481 'vlan':561,563,565,691,722,760,776,2799,2804,2818,2822,2825,3089 'vlan10':777 'vlan20':785 'vlan30':793 'volum':1453 'vpn':601 'vulner':114,137 'w':2469,2476,2483,2490,2497,2518,2525,2532,2539 'wa':2479,2486,2500,2528,2535 'warn':436,2339 'watchdog':1631,1909,1930,1937,1992,1996,3198 'watchdog-devic':1991 'watchdog-timeout':1995 'wide':338 'wifi':616,737,1600 'wire':2821 'wireless':1592 'within':1953 'wjalrxutnfemi/k7mdeng/bpxrficyexamplekey':1089 'wlan0':728 'work':3171 'workdir':1338 'workspac':1629 'workstat':915 'wrap':230 'write':519,2062,2249 'wrong':196 'x':633,1559,1568,1836,1844,1868,1880,1886,1902,2315,2317,2330,2345,2414,2431,2451,2542,2608 'x00':1973 'x11forwarding':897 'xml':334,341,360,824,2976 'y':967,983,1028,1040,1178,1284,1388,2073 'yaml':765,1074,1090,1429,2849 'yes':884 'z':1846,1854,2319,2321,2335,2349,2416,2426,2433,2441,2455,2457,2458 'zero':1928,3200 'zone':3093","prices":[{"id":"f8c052f0-5d78-4c66-8282-e353dade409e","listingId":"31f39e45-02e9-40ed-a0c7-dc140955133d","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"arpitg1304","category":"robotics-agent-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:05:36.010Z"}],"sources":[{"listingId":"31f39e45-02e9-40ed-a0c7-dc140955133d","source":"github","sourceId":"arpitg1304/robotics-agent-skills/robotics-security","sourceUrl":"https://github.com/arpitg1304/robotics-agent-skills/tree/main/skills/robotics-security","isPrimary":false,"firstSeenAt":"2026-04-18T22:05:36.010Z","lastSeenAt":"2026-05-02T18:54:20.988Z"}],"details":{"listingId":"31f39e45-02e9-40ed-a0c7-dc140955133d","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"arpitg1304","slug":"robotics-security","github":{"repo":"arpitg1304/robotics-agent-skills","stars":189,"topics":["agent-skills","ai-coding-assistant","claude-skills","robotics"],"license":"apache-2.0","html_url":"https://github.com/arpitg1304/robotics-agent-skills","pushed_at":"2026-03-25T03:44:12Z","description":"Agent skills that make AI coding assistants write production-grade robotics software. ROS1, ROS2, design patterns, SOLID principles, and testing — for Claude Code, Cursor, Copilot, and any SKILL.md-compatible agent.","skill_md_sha":"b464e2cb7718822ced54eb7340b4eecfb8f2b13e","skill_md_path":"skills/robotics-security/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/arpitg1304/robotics-agent-skills/tree/main/skills/robotics-security"},"layout":"multi","source":"github","category":"robotics-agent-skills","frontmatter":{"name":"robotics-security","description":"Security hardening and best practices for robotic systems, covering SROS2 DDS security, network segmentation, secrets management, secure boot, and the physical-cyber safety intersection. Use this skill when securing ROS2 communications, configuring DDS encryption and access control, hardening robot onboard computers, managing certificates and credentials, setting up network segmentation for robot fleets, or addressing the unique security challenges where cyber vulnerabilities become physical safety risks. Trigger whenever the user mentions SROS2, DDS security, robot security, robot hardening, ROS2 encryption, ROS2 access control, robot network security, secure robot deployment, robot certificates, keystore generation, robot firewall, e-stop security, safety controller isolation, or IEC 62443 for robotics."},"skills_sh_url":"https://skills.sh/arpitg1304/robotics-agent-skills/robotics-security"},"updatedAt":"2026-05-02T18:54:20.988Z"}}