Skip to content

OAuth Callback Insecure Deserialization in doubleleft/hook #159

Description

@fa1c4

OAuth Callback Insecure Deserialization in doubleleft/hook

1. Bug Topic

POST /oauth/callback accepts attacker-controlled opauth data and passes it to
PHP unserialize().

2. Release Version / Commit Hash / Affected Range

  • Affected source snapshot: InvAudit package 0964_doubleleft__hook_minimal(1).zip
  • InvAudit run id: 20260625-103459-39ce453e
  • Exact commit hash: unknown; .git metadata was not present in the provided
    minimal package.
  • Affected range: source versions where
    src/Controllers/OAuthController.php::auth() contains
    unserialize(base64_decode($_POST['opauth'])) and src/Application/Routes.php
    maps POST /oauth/callback to that method.

3. Bug Type

Insecure Deserialization / PHP Object Injection.

4. CWE

CWE-502: Deserialization of Untrusted Data.

5. Bug Summary

The OAuth callback endpoint deserializes the user-controlled opauth POST
parameter. An attacker can submit a base64-encoded serialized PHP object to the
callback route. PHP object magic methods execute during unserialize() before
Hook validates the payload.

6. Root Cause

The controller treats an HTTP POST parameter as trusted serialized PHP data:

$opauth = unserialize(base64_decode($_POST['opauth']));

This happens without class restrictions, cryptographic verification before
deserialization, or use of a safer data-only format.

7. Attack Preconditions

  • The attacker can send a POST request to /oauth/callback.
  • The attacker can include the opauth form field.
  • The request includes a valid Hook app id/key where required by the deployment.
    Hook browser/device keys are designed for client/front-end use and therefore
    should not be treated as user authentication secrets.
  • Impact depends on available application classes/gadget chains.

8. Impact Analysis

The bug permits attacker-controlled PHP object deserialization. The standalone
PoC demonstrates execution of __wakeup() from an HTTP POST request. In a real
application, available gadget chains may turn this into file writes, command
execution, data modification, or other application-specific side effects.

9. Affected Code

Route registration in src/Application/Routes.php:

$app->post($path . 'oauth/callback', 'Hook\\Controllers\\OAuthController:auth');

Vulnerable sink in src/Controllers/OAuthController.php:

if (isset($_POST['opauth'])) {
    $opauth = unserialize(base64_decode($_POST['opauth']));

10. PoC

The PoC is in: https://github.com/fa1c4/security-advisories/tree/main/doubleleft_hook

Expected vulnerable output:

Marker created: yes
__wakeup executed via opauth POST
[VULNERABLE] Attacker-controlled opauth POST data reached PHP unserialize() and executed object magic method.

11. Expected Result

The OAuth callback should not deserialize attacker-controlled PHP objects. A fix
should prefer a data-only format such as JSON. If legacy serialized data must be
accepted, the code should verify authenticity before deserialization and prevent
object instantiation with allowed_classes => false or a strict whitelist, then
validate the resulting array schema before use.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions