VYPR
Moderate severityNVD Advisory· Published Feb 1, 2024· Updated Feb 13, 2025

Vault May Expose Sensitive Information When Configuring An Audit Log Device

CVE-2024-0831

Description

Vault and Vault Enterprise (“Vault”) may expose sensitive information when enabling an audit device which specifies the log_raw option, which may log sensitive information to other audit devices, regardless of whether they are configured to use log_raw.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/hashicorp/vaultGo
>= 1.15.0, < 1.15.51.15.5

Affected products

2
  • Range: 1.15.0
  • HashiCorp/Vault Enterprisev5
    Range: 1.15.0

Patches

1
2a72f2a8a5b5

VAULT-23122: Audit fix for 'log_raw' issue (#24968) (#24974)

https://github.com/hashicorp/vaulthc-github-team-secure-vault-coreJan 22, 2024via ghsa
10 files changed · +461 79
  • audit/entry_formatter.go+20 4 modified
    @@ -80,7 +80,7 @@ func (f *EntryFormatter) Process(ctx context.Context, e *eventlogger.Event) (*ev
     		return nil, fmt.Errorf("%s: event is nil: %w", op, event.ErrInvalidParameter)
     	}
     
    -	a, ok := e.Payload.(*auditEvent)
    +	a, ok := e.Payload.(*AuditEvent)
     	if !ok {
     		return nil, fmt.Errorf("%s: cannot parse event payload: %w", op, event.ErrInvalidParameter)
     	}
    @@ -155,10 +155,26 @@ func (f *EntryFormatter) Process(ctx context.Context, e *eventlogger.Event) (*ev
     		result = append([]byte(f.prefix), result...)
     	}
     
    -	// Store the final format.
    -	e.FormattedAs(f.config.RequiredFormat.String(), result)
    +	// Copy some properties from the event (and audit event) and store the
    +	// format for the next (sink) node to Process.
    +	a2 := &AuditEvent{
    +		ID:        a.ID,
    +		Version:   a.Version,
    +		Subtype:   a.Subtype,
    +		Timestamp: a.Timestamp,
    +		Data:      data, // Use the cloned data here rather than a pointer to the original.
    +	}
    +
    +	e2 := &eventlogger.Event{
    +		Type:      e.Type,
    +		CreatedAt: e.CreatedAt,
    +		Formatted: make(map[string][]byte), // we are about to set this ourselves.
    +		Payload:   a2,
    +	}
    +
    +	e2.FormattedAs(f.config.RequiredFormat.String(), result)
     
    -	return e, nil
    +	return e2, nil
     }
     
     // FormatRequest attempts to format the specified logical.LogInput into a RequestEntry.
    
  • audit/entry_formatter_test.go+408 43 modified
    @@ -5,49 +5,23 @@ package audit
     
     import (
     	"context"
    +	"encoding/json"
    +	"errors"
    +	"fmt"
    +	"strings"
     	"testing"
     	"time"
     
    -	"github.com/hashicorp/vault/internal/observability/event"
    -
    +	"github.com/hashicorp/eventlogger"
     	"github.com/hashicorp/vault/helper/namespace"
    -
    +	"github.com/hashicorp/vault/internal/observability/event"
    +	"github.com/hashicorp/vault/sdk/helper/jsonutil"
    +	"github.com/hashicorp/vault/sdk/helper/salt"
     	"github.com/hashicorp/vault/sdk/logical"
    -
    -	"github.com/hashicorp/eventlogger"
    +	"github.com/mitchellh/copystructure"
     	"github.com/stretchr/testify/require"
     )
     
    -// fakeEvent will return a new fake event containing audit data based  on the
    -// specified subtype, format and logical.LogInput.
    -func fakeEvent(tb testing.TB, subtype subtype, format format, input *logical.LogInput) *eventlogger.Event {
    -	tb.Helper()
    -
    -	date := time.Date(2023, time.July, 11, 15, 49, 10, 0o0, time.Local)
    -
    -	auditEvent, err := NewEvent(subtype,
    -		WithID("123"),
    -		WithNow(date),
    -	)
    -	require.NoError(tb, err)
    -	require.NotNil(tb, auditEvent)
    -	require.Equal(tb, "123", auditEvent.ID)
    -	require.Equal(tb, "v0.1", auditEvent.Version)
    -	require.Equal(tb, subtype, auditEvent.Subtype)
    -	require.Equal(tb, date, auditEvent.Timestamp)
    -
    -	auditEvent.Data = input
    -
    -	e := &eventlogger.Event{
    -		Type:      eventlogger.EventType(event.AuditType),
    -		CreatedAt: auditEvent.Timestamp,
    -		Formatted: make(map[string][]byte),
    -		Payload:   auditEvent,
    -	}
    -
    -	return e
    -}
    -
     // TestNewEntryFormatter ensures we can create new EntryFormatter structs.
     func TestNewEntryFormatter(t *testing.T) {
     	tests := map[string]struct {
    @@ -297,7 +271,7 @@ func TestEntryFormatter_Process(t *testing.T) {
     		tc := tc
     		t.Run(name, func(t *testing.T) {
     			t.Parallel()
    -			e := fakeEvent(t, tc.Subtype, tc.RequiredFormat, tc.Data)
    +			e := fakeEvent(t, tc.Subtype, tc.Data)
     			require.NotNil(t, e)
     
     			ss := newStaticSalt(t)
    @@ -317,18 +291,16 @@ func TestEntryFormatter_Process(t *testing.T) {
     			}
     
     			processed, err := f.Process(ctx, e)
    -			b, found := e.Format(string(tc.RequiredFormat))
     
     			switch {
     			case tc.IsErrorExpected:
     				require.Error(t, err)
     				require.EqualError(t, err, tc.ExpectedErrorMessage)
     				require.Nil(t, processed)
    -				require.False(t, found)
    -				require.Nil(t, b)
     			default:
     				require.NoError(t, err)
     				require.NotNil(t, processed)
    +				b, found := processed.Format(string(tc.RequiredFormat))
     				require.True(t, found)
     				require.NotNil(t, b)
     			}
    @@ -381,20 +353,413 @@ func BenchmarkAuditFileSink_Process(b *testing.B) {
     	require.NotNil(b, sink)
     
     	// Generate the event
    -	event := fakeEvent(b, RequestType, JSONFormat, in)
    -	require.NotNil(b, event)
    +	e := fakeEvent(b, RequestType, in)
    +	require.NotNil(b, e)
     
     	b.ResetTimer()
     	b.RunParallel(func(pb *testing.PB) {
     		for pb.Next() {
    -			event, err = formatter.Process(ctx, event)
    +			e2, err := formatter.Process(ctx, e)
     			if err != nil {
     				panic(err)
     			}
    -			_, err := sink.Process(ctx, event)
    +			_, err = sink.Process(ctx, e2)
     			if err != nil {
     				panic(err)
     			}
     		}
     	})
     }
    +
    +// TestEntryFormatter_Process_JSON ensures that the JSON output we get matches what
    +// we expect for the specified LogInput.
    +func TestEntryFormatter_Process_JSON(t *testing.T) {
    +	ss := newStaticSalt(t)
    +
    +	expectedResultStr := fmt.Sprintf(testFormatJSONReqBasicStrFmt, ss.salt.GetIdentifiedHMAC("foo"))
    +
    +	issueTime, _ := time.Parse(time.RFC3339, "2020-05-28T13:40:18-05:00")
    +	cases := map[string]struct {
    +		Auth        *logical.Auth
    +		Req         *logical.Request
    +		Err         error
    +		Prefix      string
    +		ExpectedStr string
    +	}{
    +		"auth, request": {
    +			&logical.Auth{
    +				ClientToken:     "foo",
    +				Accessor:        "bar",
    +				DisplayName:     "testtoken",
    +				EntityID:        "foobarentity",
    +				NoDefaultPolicy: true,
    +				Policies:        []string{"root"},
    +				TokenType:       logical.TokenTypeService,
    +				LeaseOptions: logical.LeaseOptions{
    +					TTL:       time.Hour * 4,
    +					IssueTime: issueTime,
    +				},
    +			},
    +			&logical.Request{
    +				Operation: logical.UpdateOperation,
    +				Path:      "/foo",
    +				Connection: &logical.Connection{
    +					RemoteAddr: "127.0.0.1",
    +				},
    +				WrapInfo: &logical.RequestWrapInfo{
    +					TTL: 60 * time.Second,
    +				},
    +				Headers: map[string][]string{
    +					"foo": {"bar"},
    +				},
    +			},
    +			errors.New("this is an error"),
    +			"",
    +			expectedResultStr,
    +		},
    +		"auth, request with prefix": {
    +			&logical.Auth{
    +				ClientToken:     "foo",
    +				Accessor:        "bar",
    +				EntityID:        "foobarentity",
    +				DisplayName:     "testtoken",
    +				NoDefaultPolicy: true,
    +				Policies:        []string{"root"},
    +				TokenType:       logical.TokenTypeService,
    +				LeaseOptions: logical.LeaseOptions{
    +					TTL:       time.Hour * 4,
    +					IssueTime: issueTime,
    +				},
    +			},
    +			&logical.Request{
    +				Operation: logical.UpdateOperation,
    +				Path:      "/foo",
    +				Connection: &logical.Connection{
    +					RemoteAddr: "127.0.0.1",
    +				},
    +				WrapInfo: &logical.RequestWrapInfo{
    +					TTL: 60 * time.Second,
    +				},
    +				Headers: map[string][]string{
    +					"foo": {"bar"},
    +				},
    +			},
    +			errors.New("this is an error"),
    +			"@cee: ",
    +			expectedResultStr,
    +		},
    +	}
    +
    +	for name, tc := range cases {
    +		cfg, err := NewFormatterConfig(WithHMACAccessor(false))
    +		require.NoError(t, err)
    +		formatter, err := NewEntryFormatter(cfg, ss, WithPrefix(tc.Prefix))
    +		require.NoError(t, err)
    +
    +		in := &logical.LogInput{
    +			Auth:     tc.Auth,
    +			Request:  tc.Req,
    +			OuterErr: tc.Err,
    +		}
    +
    +		// Create an audit event and more generic eventlogger.event to allow us
    +		// to process (format).
    +		auditEvent, err := NewEvent(RequestType)
    +		require.NoError(t, err)
    +		auditEvent.Data = in
    +
    +		e := &eventlogger.Event{
    +			Type:      eventlogger.EventType(event.AuditType.String()),
    +			CreatedAt: time.Now(),
    +			Formatted: make(map[string][]byte),
    +			Payload:   auditEvent,
    +		}
    +
    +		e2, err := formatter.Process(namespace.RootContext(nil), e)
    +		require.NoErrorf(t, err, "bad: %s\nerr: %s", name, err)
    +
    +		jsonBytes, ok := e2.Format(JSONFormat.String())
    +		require.True(t, ok)
    +		require.Positive(t, len(jsonBytes))
    +
    +		if !strings.HasPrefix(string(jsonBytes), tc.Prefix) {
    +			t.Fatalf("no prefix: %s \n log: %s\nprefix: %s", name, expectedResultStr, tc.Prefix)
    +		}
    +
    +		expectedJSON := new(RequestEntry)
    +
    +		if err := jsonutil.DecodeJSON([]byte(expectedResultStr), &expectedJSON); err != nil {
    +			t.Fatalf("bad json: %s", err)
    +		}
    +		expectedJSON.Request.Namespace = &Namespace{ID: "root"}
    +
    +		actualJSON := new(RequestEntry)
    +		if err := jsonutil.DecodeJSON(jsonBytes[len(tc.Prefix):], &actualJSON); err != nil {
    +			t.Fatalf("bad json: %s", err)
    +		}
    +
    +		expectedJSON.Time = actualJSON.Time
    +
    +		expectedBytes, err := json.Marshal(expectedJSON)
    +		if err != nil {
    +			t.Fatalf("unable to marshal json: %s", err)
    +		}
    +
    +		if !strings.HasSuffix(strings.TrimSpace(string(jsonBytes)), string(expectedBytes)) {
    +			t.Fatalf("bad: %s\nResult:\n\n%q\n\nExpected:\n\n%q", name, string(jsonBytes), string(expectedBytes))
    +		}
    +	}
    +}
    +
    +// TestEntryFormatter_Process_JSONx ensures that the JSONx output we get matches what
    +// we expect for the specified LogInput.
    +func TestEntryFormatter_Process_JSONx(t *testing.T) {
    +	s, err := salt.NewSalt(context.Background(), nil, nil)
    +	require.NoError(t, err)
    +	tempStaticSalt := &staticSalt{salt: s}
    +
    +	fooSalted := s.GetIdentifiedHMAC("foo")
    +	issueTime, _ := time.Parse(time.RFC3339, "2020-05-28T13:40:18-05:00")
    +
    +	cases := map[string]struct {
    +		Auth        *logical.Auth
    +		Req         *logical.Request
    +		Err         error
    +		Prefix      string
    +		Result      string
    +		ExpectedStr string
    +	}{
    +		"auth, request": {
    +			&logical.Auth{
    +				ClientToken:     "foo",
    +				Accessor:        "bar",
    +				DisplayName:     "testtoken",
    +				EntityID:        "foobarentity",
    +				NoDefaultPolicy: true,
    +				Policies:        []string{"root"},
    +				TokenType:       logical.TokenTypeService,
    +				LeaseOptions: logical.LeaseOptions{
    +					TTL:       time.Hour * 4,
    +					IssueTime: issueTime,
    +				},
    +			},
    +			&logical.Request{
    +				ID:                  "request",
    +				ClientToken:         "foo",
    +				ClientTokenAccessor: "bar",
    +				Operation:           logical.UpdateOperation,
    +				Path:                "/foo",
    +				Connection: &logical.Connection{
    +					RemoteAddr: "127.0.0.1",
    +				},
    +				WrapInfo: &logical.RequestWrapInfo{
    +					TTL: 60 * time.Second,
    +				},
    +				Headers: map[string][]string{
    +					"foo": {"bar"},
    +				},
    +				PolicyOverride: true,
    +			},
    +			errors.New("this is an error"),
    +			"",
    +			"",
    +			fmt.Sprintf(`<json:object name="auth"><json:string name="accessor">bar</json:string><json:string name="client_token">%s</json:string><json:string name="display_name">testtoken</json:string><json:string name="entity_id">foobarentity</json:string><json:boolean name="no_default_policy">true</json:boolean><json:array name="policies"><json:string>root</json:string></json:array><json:string name="token_issue_time">2020-05-28T13:40:18-05:00</json:string><json:number name="token_ttl">14400</json:number><json:string name="token_type">service</json:string></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token">%s</json:string><json:string name="client_token_accessor">bar</json:string><json:object name="headers"><json:array name="foo"><json:string>bar</json:string></json:array></json:object><json:string name="id">request</json:string><json:object name="namespace"><json:string name="id">root</json:string></json:object><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:boolean name="policy_override">true</json:boolean><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
    +				fooSalted, fooSalted),
    +		},
    +		"auth, request with prefix": {
    +			&logical.Auth{
    +				ClientToken:     "foo",
    +				Accessor:        "bar",
    +				DisplayName:     "testtoken",
    +				NoDefaultPolicy: true,
    +				EntityID:        "foobarentity",
    +				Policies:        []string{"root"},
    +				TokenType:       logical.TokenTypeService,
    +				LeaseOptions: logical.LeaseOptions{
    +					TTL:       time.Hour * 4,
    +					IssueTime: issueTime,
    +				},
    +			},
    +			&logical.Request{
    +				ID:                  "request",
    +				ClientToken:         "foo",
    +				ClientTokenAccessor: "bar",
    +				Operation:           logical.UpdateOperation,
    +				Path:                "/foo",
    +				Connection: &logical.Connection{
    +					RemoteAddr: "127.0.0.1",
    +				},
    +				WrapInfo: &logical.RequestWrapInfo{
    +					TTL: 60 * time.Second,
    +				},
    +				Headers: map[string][]string{
    +					"foo": {"bar"},
    +				},
    +				PolicyOverride: true,
    +			},
    +			errors.New("this is an error"),
    +			"",
    +			"@cee: ",
    +			fmt.Sprintf(`<json:object name="auth"><json:string name="accessor">bar</json:string><json:string name="client_token">%s</json:string><json:string name="display_name">testtoken</json:string><json:string name="entity_id">foobarentity</json:string><json:boolean name="no_default_policy">true</json:boolean><json:array name="policies"><json:string>root</json:string></json:array><json:string name="token_issue_time">2020-05-28T13:40:18-05:00</json:string><json:number name="token_ttl">14400</json:number><json:string name="token_type">service</json:string></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token">%s</json:string><json:string name="client_token_accessor">bar</json:string><json:object name="headers"><json:array name="foo"><json:string>bar</json:string></json:array></json:object><json:string name="id">request</json:string><json:object name="namespace"><json:string name="id">root</json:string></json:object><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:boolean name="policy_override">true</json:boolean><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
    +				fooSalted, fooSalted),
    +		},
    +	}
    +
    +	for name, tc := range cases {
    +		cfg, err := NewFormatterConfig(
    +			WithOmitTime(true),
    +			WithHMACAccessor(false),
    +			WithFormat(JSONxFormat.String()),
    +		)
    +		require.NoError(t, err)
    +		formatter, err := NewEntryFormatter(cfg, tempStaticSalt, WithPrefix(tc.Prefix))
    +		require.NoError(t, err)
    +		require.NotNil(t, formatter)
    +
    +		in := &logical.LogInput{
    +			Auth:     tc.Auth,
    +			Request:  tc.Req,
    +			OuterErr: tc.Err,
    +		}
    +
    +		// Create an audit event and more generic eventlogger.event to allow us
    +		// to process (format).
    +		auditEvent, err := NewEvent(RequestType)
    +		require.NoError(t, err)
    +		auditEvent.Data = in
    +
    +		e := &eventlogger.Event{
    +			Type:      eventlogger.EventType(event.AuditType.String()),
    +			CreatedAt: time.Now(),
    +			Formatted: make(map[string][]byte),
    +			Payload:   auditEvent,
    +		}
    +
    +		e2, err := formatter.Process(namespace.RootContext(nil), e)
    +		require.NoErrorf(t, err, "bad: %s\nerr: %s", name, err)
    +
    +		jsonxBytes, ok := e2.Format(JSONxFormat.String())
    +		require.True(t, ok)
    +		require.Positive(t, len(jsonxBytes))
    +
    +		if !strings.HasPrefix(string(jsonxBytes), tc.Prefix) {
    +			t.Fatalf("no prefix: %s \n log: %s\nprefix: %s", name, tc.Result, tc.Prefix)
    +		}
    +
    +		if !strings.HasSuffix(strings.TrimSpace(string(jsonxBytes)), string(tc.ExpectedStr)) {
    +			t.Fatalf(
    +				"bad: %s\nResult:\n\n%q\n\nExpected:\n\n%q",
    +				name, strings.TrimSpace(string(jsonxBytes)), string(tc.ExpectedStr))
    +		}
    +	}
    +}
    +
    +// TestEntryFormatter_Process_NoMutation tests that the event returned by an
    +// EntryFormatter.Process method is not the same as the one that it accepted.
    +func TestEntryFormatter_Process_NoMutation(t *testing.T) {
    +	// Create the formatter node.
    +	cfg, err := NewFormatterConfig()
    +	require.NoError(t, err)
    +	ss := newStaticSalt(t)
    +	formatter, err := NewEntryFormatter(cfg, ss)
    +	require.NoError(t, err)
    +	require.NotNil(t, formatter)
    +
    +	in := &logical.LogInput{
    +		Auth: &logical.Auth{
    +			ClientToken:     "foo",
    +			Accessor:        "bar",
    +			EntityID:        "foobarentity",
    +			DisplayName:     "testtoken",
    +			NoDefaultPolicy: true,
    +			Policies:        []string{"root"},
    +			TokenType:       logical.TokenTypeService,
    +		},
    +		Request: &logical.Request{
    +			Operation: logical.UpdateOperation,
    +			Path:      "/foo",
    +			Connection: &logical.Connection{
    +				RemoteAddr: "127.0.0.1",
    +			},
    +			WrapInfo: &logical.RequestWrapInfo{
    +				TTL: 60 * time.Second,
    +			},
    +			Headers: map[string][]string{
    +				"foo": {"bar"},
    +			},
    +		},
    +	}
    +
    +	e := fakeEvent(t, RequestType, in)
    +
    +	e2, err := formatter.Process(namespace.RootContext(nil), e)
    +	require.NoError(t, err)
    +	require.NotNil(t, e2)
    +
    +	// Ensure the pointers are different.
    +	require.NotEqual(t, e2, e)
    +
    +	// Do the same for the audit event in the payload.
    +	a, ok := e.Payload.(*AuditEvent)
    +	require.True(t, ok)
    +	require.NotNil(t, a)
    +
    +	a2, ok := e2.Payload.(*AuditEvent)
    +	require.True(t, ok)
    +	require.NotNil(t, a2)
    +
    +	require.NotEqual(t, a2, a)
    +}
    +
    +// hashExpectedValueForComparison replicates enough of the audit HMAC process on a piece of expected data in a test,
    +// so that we can use assert.Equal to compare the expected and output values.
    +func (f *EntryFormatter) hashExpectedValueForComparison(input map[string]any) map[string]any {
    +	// Copy input before modifying, since we may re-use the same data in another test
    +	copied, err := copystructure.Copy(input)
    +	if err != nil {
    +		panic(err)
    +	}
    +	copiedAsMap := copied.(map[string]any)
    +
    +	s, err := f.salter.Salt(context.Background())
    +	if err != nil {
    +		panic(err)
    +	}
    +
    +	err = hashMap(s.GetIdentifiedHMAC, copiedAsMap, nil)
    +	if err != nil {
    +		panic(err)
    +	}
    +
    +	return copiedAsMap
    +}
    +
    +// fakeEvent will return a new fake event containing audit data based  on the
    +// specified subtype, format and logical.LogInput.
    +func fakeEvent(tb testing.TB, subtype subtype, input *logical.LogInput) *eventlogger.Event {
    +	tb.Helper()
    +
    +	date := time.Date(2023, time.July, 11, 15, 49, 10, 0o0, time.Local)
    +
    +	auditEvent, err := NewEvent(subtype,
    +		WithID("123"),
    +		WithNow(date),
    +	)
    +	require.NoError(tb, err)
    +	require.NotNil(tb, auditEvent)
    +	require.Equal(tb, "123", auditEvent.ID)
    +	require.Equal(tb, "v0.1", auditEvent.Version)
    +	require.Equal(tb, subtype, auditEvent.Subtype)
    +	require.Equal(tb, date, auditEvent.Timestamp)
    +
    +	auditEvent.Data = input
    +
    +	e := &eventlogger.Event{
    +		Type:      eventlogger.EventType(event.AuditType),
    +		CreatedAt: auditEvent.Timestamp,
    +		Formatted: make(map[string][]byte),
    +		Payload:   auditEvent,
    +	}
    +
    +	return e
    +}
    
  • audit/event.go+5 5 modified
    @@ -12,8 +12,8 @@ import (
     // NewEvent should be used to create an audit event. The subtype field is needed
     // for audit events. It will generate an ID if no ID is supplied. Supported
     // options: WithID, WithNow.
    -func NewEvent(s subtype, opt ...Option) (*auditEvent, error) {
    -	const op = "audit.newEvent"
    +func NewEvent(s subtype, opt ...Option) (*AuditEvent, error) {
    +	const op = "audit.NewEvent"
     
     	// Get the default options
     	opts, err := getOpts(opt...)
    @@ -30,7 +30,7 @@ func NewEvent(s subtype, opt ...Option) (*auditEvent, error) {
     		}
     	}
     
    -	audit := &auditEvent{
    +	audit := &AuditEvent{
     		ID:        opts.withID,
     		Timestamp: opts.withNow,
     		Version:   version,
    @@ -44,8 +44,8 @@ func NewEvent(s subtype, opt ...Option) (*auditEvent, error) {
     }
     
     // validate attempts to ensure the audit event in its present state is valid.
    -func (a *auditEvent) validate() error {
    -	const op = "audit.(auditEvent).validate"
    +func (a *AuditEvent) validate() error {
    +	const op = "audit.(AuditEvent).validate"
     
     	if a == nil {
     		return fmt.Errorf("%s: event is nil: %w", op, event.ErrInvalidParameter)
    
  • audit/event_test.go+16 16 modified
    @@ -29,21 +29,21 @@ func TestAuditEvent_new(t *testing.T) {
     			Subtype:              subtype(""),
     			Format:               format(""),
     			IsErrorExpected:      true,
    -			ExpectedErrorMessage: "audit.newEvent: audit.(auditEvent).validate: audit.(subtype).validate: '' is not a valid event subtype: invalid parameter",
    +			ExpectedErrorMessage: "audit.NewEvent: audit.(AuditEvent).validate: audit.(subtype).validate: '' is not a valid event subtype: invalid parameter",
     		},
     		"empty-Option": {
     			Options:              []Option{},
     			Subtype:              subtype(""),
     			Format:               format(""),
     			IsErrorExpected:      true,
    -			ExpectedErrorMessage: "audit.newEvent: audit.(auditEvent).validate: audit.(subtype).validate: '' is not a valid event subtype: invalid parameter",
    +			ExpectedErrorMessage: "audit.NewEvent: audit.(AuditEvent).validate: audit.(subtype).validate: '' is not a valid event subtype: invalid parameter",
     		},
     		"bad-id": {
     			Options:              []Option{WithID("")},
     			Subtype:              ResponseType,
     			Format:               JSONFormat,
     			IsErrorExpected:      true,
    -			ExpectedErrorMessage: "audit.newEvent: error applying options: id cannot be empty",
    +			ExpectedErrorMessage: "audit.NewEvent: error applying options: id cannot be empty",
     		},
     		"good": {
     			Options: []Option{
    @@ -108,66 +108,66 @@ func TestAuditEvent_new(t *testing.T) {
     // TestAuditEvent_Validate exercises the validation for an audit event.
     func TestAuditEvent_Validate(t *testing.T) {
     	tests := map[string]struct {
    -		Value                *auditEvent
    +		Value                *AuditEvent
     		IsErrorExpected      bool
     		ExpectedErrorMessage string
     	}{
     		"nil": {
     			Value:                nil,
     			IsErrorExpected:      true,
    -			ExpectedErrorMessage: "audit.(auditEvent).validate: event is nil: invalid parameter",
    +			ExpectedErrorMessage: "audit.(AuditEvent).validate: event is nil: invalid parameter",
     		},
     		"default": {
    -			Value:                &auditEvent{},
    +			Value:                &AuditEvent{},
     			IsErrorExpected:      true,
    -			ExpectedErrorMessage: "audit.(auditEvent).validate: missing ID: invalid parameter",
    +			ExpectedErrorMessage: "audit.(AuditEvent).validate: missing ID: invalid parameter",
     		},
     		"id-empty": {
    -			Value: &auditEvent{
    +			Value: &AuditEvent{
     				ID:        "",
     				Version:   version,
     				Subtype:   RequestType,
     				Timestamp: time.Now(),
     				Data:      nil,
     			},
     			IsErrorExpected:      true,
    -			ExpectedErrorMessage: "audit.(auditEvent).validate: missing ID: invalid parameter",
    +			ExpectedErrorMessage: "audit.(AuditEvent).validate: missing ID: invalid parameter",
     		},
     		"version-fiddled": {
    -			Value: &auditEvent{
    +			Value: &AuditEvent{
     				ID:        "audit_123",
     				Version:   "magic-v2",
     				Subtype:   RequestType,
     				Timestamp: time.Now(),
     				Data:      nil,
     			},
     			IsErrorExpected:      true,
    -			ExpectedErrorMessage: "audit.(auditEvent).validate: event version unsupported: invalid parameter",
    +			ExpectedErrorMessage: "audit.(AuditEvent).validate: event version unsupported: invalid parameter",
     		},
     		"subtype-fiddled": {
    -			Value: &auditEvent{
    +			Value: &AuditEvent{
     				ID:        "audit_123",
     				Version:   version,
     				Subtype:   subtype("moon"),
     				Timestamp: time.Now(),
     				Data:      nil,
     			},
     			IsErrorExpected:      true,
    -			ExpectedErrorMessage: "audit.(auditEvent).validate: audit.(subtype).validate: 'moon' is not a valid event subtype: invalid parameter",
    +			ExpectedErrorMessage: "audit.(AuditEvent).validate: audit.(subtype).validate: 'moon' is not a valid event subtype: invalid parameter",
     		},
     		"default-time": {
    -			Value: &auditEvent{
    +			Value: &AuditEvent{
     				ID:        "audit_123",
     				Version:   version,
     				Subtype:   ResponseType,
     				Timestamp: time.Time{},
     				Data:      nil,
     			},
     			IsErrorExpected:      true,
    -			ExpectedErrorMessage: "audit.(auditEvent).validate: event timestamp cannot be the zero time instant: invalid parameter",
    +			ExpectedErrorMessage: "audit.(AuditEvent).validate: event timestamp cannot be the zero time instant: invalid parameter",
     		},
     		"valid": {
    -			Value: &auditEvent{
    +			Value: &AuditEvent{
     				ID:        "audit_123",
     				Version:   version,
     				Subtype:   ResponseType,
    
  • audit/sink_wrapper.go+2 2 modified
    @@ -12,7 +12,7 @@ import (
     )
     
     // SinkWrapper is a wrapper for any kind of Sink Node that processes events
    -// containing an auditEvent payload.
    +// containing an AuditEvent payload.
     type SinkWrapper struct {
     	Name string
     	Sink eventlogger.Node
    @@ -23,7 +23,7 @@ type SinkWrapper struct {
     // once this method returns.
     func (s *SinkWrapper) Process(ctx context.Context, e *eventlogger.Event) (*eventlogger.Event, error) {
     	defer func() {
    -		auditEvent, ok := e.Payload.(*auditEvent)
    +		auditEvent, ok := e.Payload.(*AuditEvent)
     		if ok {
     			metrics.MeasureSince([]string{"audit", s.Name, auditEvent.Subtype.MetricTag()}, e.CreatedAt)
     		}
    
  • audit/types.go+2 2 modified
    @@ -35,8 +35,8 @@ type subtype string
     // format defines types of format audit events support.
     type format string
     
    -// auditEvent is the audit event.
    -type auditEvent struct {
    +// AuditEvent is the audit event.
    +type AuditEvent struct {
     	ID        string            `json:"id"`
     	Version   string            `json:"version"`
     	Subtype   subtype           `json:"subtype"` // the subtype of the audit event.
    
  • changelog/24968.txt+3 0 added
    @@ -0,0 +1,3 @@
    +```release-note:bug
    +audit: Fix bug where use of 'log_raw' option could result in other devices logging raw audit data
    +```
    
  • internal/observability/event/sink_socket.go+1 2 modified
    @@ -10,9 +10,8 @@ import (
     	"sync"
     	"time"
     
    -	"github.com/hashicorp/go-multierror"
    -
     	"github.com/hashicorp/eventlogger"
    +	"github.com/hashicorp/go-multierror"
     )
     
     var _ eventlogger.Node = (*SocketSink)(nil)
    
  • internal/observability/event/sink_stdout.go+3 3 modified
    @@ -28,7 +28,7 @@ func NewStdoutSinkNode(format string) *StdoutSink {
     }
     
     // Process persists the provided eventlogger.Event to the standard output stream.
    -func (s *StdoutSink) Process(ctx context.Context, event *eventlogger.Event) (*eventlogger.Event, error) {
    +func (s *StdoutSink) Process(ctx context.Context, e *eventlogger.Event) (*eventlogger.Event, error) {
     	const op = "event.(StdoutSink).Process"
     
     	select {
    @@ -37,11 +37,11 @@ func (s *StdoutSink) Process(ctx context.Context, event *eventlogger.Event) (*ev
     	default:
     	}
     
    -	if event == nil {
    +	if e == nil {
     		return nil, fmt.Errorf("%s: event is nil: %w", op, ErrInvalidParameter)
     	}
     
    -	formattedBytes, found := event.Format(s.requiredFormat)
    +	formattedBytes, found := e.Format(s.requiredFormat)
     	if !found {
     		return nil, fmt.Errorf("%s: unable to retrieve event formatted as %q", op, s.requiredFormat)
     	}
    
  • internal/observability/event/sink_syslog.go+1 2 modified
    @@ -7,9 +7,8 @@ import (
     	"context"
     	"fmt"
     
    -	gsyslog "github.com/hashicorp/go-syslog"
    -
     	"github.com/hashicorp/eventlogger"
    +	gsyslog "github.com/hashicorp/go-syslog"
     )
     
     var _ eventlogger.Node = (*SyslogSink)(nil)
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.