Skip to content

Access tokens and unhashed PII are serialized into the Messenger transport #17

Description

@loevgaard

Problem

SendEvent carries the full Setono\MetaConversionsApi\Event\Event object. At dispatch time (DispatchOnCommandBusSubscriber) that object contains:

  • $event->pixels: Pixel objects including accessToken, populated by PopulatePixelsSubscriber from the pixels configuration.
  • $event->userData: raw email, phone, names, date of birth, external ids, exactly as the application set them. Normalisation and SHA-256 hashing only happen in Parameters::getPayload(), which is called inside Client::sendEvent() in the handler.

When the application routes SendEvent to an async transport (the recommended setup), the PHP-serialized message with the access token and the unhashed personal data is written to the transport storage (Doctrine table, Redis, AMQP, SQS), to the failure transport on failure, and to anything that dumps messages (messenger:failed:show, monitoring).

Impact

  • The Conversions API access token ends up in queue storage and failure transports, which are usually less protected than .env or a vault, and are rarely rotated.
  • Personal data is stored unhashed in one more system. Failure transports are often kept indefinitely, which is a retention problem under GDPR.

Suggested fix

  • Access tokens. Keep them out of the message. Strip accessToken from the pixels before dispatch and resolve tokens in the handler through a small interface (for example AccessTokenResolverInterface::resolve(string $pixelId): ?string, default implementation backed by the pixels configuration). Equivalent: split PixelProviderInterface into "which pixels apply to this request" (request time) and "token for pixel id" (send time).
  • PII. Hash on the request side: call getPayload() before dispatching and send the ready-to-post payload array plus the pixel ids and the test event code in the message, instead of the mutable Event object. This also makes the message serializable with the Symfony Serializer (the current message holds objects with untyped properties and DateTimeInterface values, which only the PHP serializer handles). If the Event object must stay in the message, document that the transport stores raw PII and the access token.

Tests

Serialize a SendEvent (or its replacement) with serialize() and assert the string contains neither the access token nor the raw email address.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions