Graylog2 / Graylog2/graylog2-server

Output configuration fields marked isEncrypted are stored in plain text when installed from a content pack

Open
#27,213 0 comments 0 reactions 0 assignees View on GitHub
bug security triaged
Dominant language
Java
Stars
8.1k
Forks
1.1k
Avg merge
1d 20h
Merged PRs (30d)
217

Description

## Expected Behavior

`MessageOutput` configuration fields declared with `isEncrypted=true` should be encrypted before being persisted, no matter which code path creates the output. Content pack installation should behave like the REST API.

## Current Behavior

`OutputFacade.decode` passes the raw configuration map straight into `outputService.create`, with no conversion of encrypted fields:

```java
final CreateOutputRequest createOutputRequest = CreateOutputRequest.create(
outputEntity.title().asString(parameters),
outputEntity.type().asString(parameters),
toValueMap(outputEntity.configuration(), parameters),
null // Outputs are assigned to streams in StreamFacade
);
```

`InputFacade.decode` does the equivalent conversion, routing the configuration through `ConfigurationWrapper` so the specialized deserializer turns plain strings into `EncryptedValue` objects:

```java
// Incoming encrypted fields from a content pack will be plain strings in the input configuration at this
// point.
// We use the object mapper to convert them into proper EncryptedValue objects. This works, because classes
// implementing the WithInputConfiguration interface will be converted using a specialized deserializer.
final var configuration = objectMapper.convertValue(
new ConfigurationWrapper(type, rawConfiguration), ConfigurationWrapper.class).configuration();
```

Result for outputs: the value lands in MongoDB as a plain `String`. `Configuration` only routes `EncryptedValue` instances into its encrypted map, so `Configuration.getEncryptedValue(key)` returns unset and the running output gets no secret.

Two concrete consequences:

1. A content pack that parameterizes the field stores the operator supplied secret in plain text in the `outputs` collection.
2. A content pack exported from a live system carries the placeholder that `ValueReference.of(EncryptedValue)` substitutes (``). Installing it stores that literal placeholder string as the field value rather than leaving the field unset.

The export side itself is fine. `ValueReference.of(EncryptedValue)` already prevents secrets from leaking into an exported content pack.

## Steps to Reproduce

1. Build a plugin output with a `TextField` declared `isEncrypted=true`, as in #26626.
2. Create a content pack containing that output, with the encrypted field exposed as a parameter.
3. Install the content pack and supply a value for the parameter.
4. Inspect the document in the `outputs` collection. The field holds the plain string, not `{ "encrypted_value": "...", "salt": "..." }`.

## Context

Follow-up to #26626 and PR #27104, which fixed the REST API create and update paths (`OutputResource`) and the load path (`OutputServiceImpl`). The content pack path was left out of scope there.

No output shipped by core or enterprise declares `isEncrypted` today, so this only affects third-party plugin outputs. It is the same class of bug as #26626 and the fix is to mirror what `InputFacade.decode` already does.

## Related

- #26626
- #27104

Contributor guide

Open the contributing guide

Research direction

Start at OutputFacade.decode and compare its output configuration handling with InputFacade.decode, especially the ConfigurationWrapper conversion before outputService.create. Verify that content-pack installation preserves encrypted fields as encrypted values, leaves exported placeholder values unset rather than storing them literally, and makes Configuration.getEncryptedValue(key) return the supplied secret.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend, security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.