safeyaml

package
v0.1.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 25, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package safeyaml provides secure YAML parsing with mandatory pre-validation.

Security Boundary

This package is the ONLY authorized entry point for YAML parsing in the codebase. Direct use of gopkg.in/yaml.v3 is prohibited except in this package and the yamlpolicy package (which provides the validation logic).

An import guard test enforces this boundary by scanning all Go files for direct yaml.v3 imports.

Why This Exists

YAML parsing is a known attack vector:

  • Alias bombs: Small YAML files can expand to huge in-memory structures via anchor/alias references (similar to XML billion-laughs attacks)

  • Memory exhaustion: Large YAML files can consume excessive memory during parsing before any application-level size checks

By centralizing YAML parsing through this package, we ensure:

  1. Size limits are enforced BEFORE parsing begins
  2. Alias bomb detection runs BEFORE the parser expands references
  3. Consistent error handling across all YAML parsing

Usage

import (
    "github.com/locktivity/epack/internal/limits"
    "github.com/locktivity/epack/internal/safeyaml"
)

var config MyConfig
if err := safeyaml.Unmarshal(data, limits.ConfigFile, &config); err != nil {
    return err
}

Package safeyaml provides secure YAML parsing with mandatory pre-validation.

Quick Start

For parsing config files:

var config Config
if err := safeyaml.Unmarshal(data, limits.ConfigFile, &config); err != nil {
    return err
}

For strict parsing (rejects unknown fields):

if err := safeyaml.UnmarshalStrict(data, limits.ConfigFile, &config); err != nil {
    return err
}

Why Not gopkg.in/yaml.v3?

This package wraps gopkg.in/yaml.v3 to ensure all YAML parsing goes through security validation BEFORE the actual parse. This prevents DoS attacks via:

  • Large file parsing (memory exhaustion)
  • YAML alias bombs (exponential expansion)

All packages needing to parse YAML should import this package instead of gopkg.in/yaml.v3 directly. An import guard test enforces this boundary.

Serialization

For marshaling (serialization), use gopkg.in/yaml.v3 directly - there are no security concerns with serialization. This package provides NewEncoder for convenience, but you can also use yaml.Marshal directly.

Index

Constants

View Source
const (
	DocumentNode = yaml.DocumentNode
	SequenceNode = yaml.SequenceNode
	MappingNode  = yaml.MappingNode
	ScalarNode   = yaml.ScalarNode
	AliasNode    = yaml.AliasNode
)

NodeKind re-exports yaml.Kind constants.

Variables

This section is empty.

Functions

func DecodeNode

func DecodeNode(data []byte, limit limits.SizeLimit) (*yaml.Node, error)

DecodeNode parses YAML into a yaml.Node tree with security validation.

SECURITY: Unlike Unmarshal to a Go type, DecodeNode preserves the node structure including anchors/aliases without expanding them. This is useful for inspection or transformation, but callers must be careful if they later convert nodes to Go types.

The yamlpolicy validation still runs to enforce size limits and detect alias bombs before the parse.

func Marshal

func Marshal(v any) ([]byte, error)

Marshal serializes a Go value to YAML. This is a passthrough to yaml.Marshal - serialization has no security concerns. Provided for convenience so packages don't need to import yaml.v3 directly.

func Unmarshal

func Unmarshal(data []byte, limit limits.SizeLimit, v any) error

Unmarshal parses YAML data into a Go value with mandatory security validation.

SECURITY: This function validates size limits and checks for alias bombs BEFORE parsing. Use this instead of yaml.Unmarshal directly.

func UnmarshalStrict

func UnmarshalStrict(data []byte, limit limits.SizeLimit, v any) error

UnmarshalStrict is like Unmarshal but returns an error for unknown fields.

Use this for configuration files where typos should be caught.

Types

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

Encoder wraps yaml.Encoder for streaming output. Use this for serialization when you need streaming writes.

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder creates a new YAML encoder writing to w.

func (*Encoder) Close

func (e *Encoder) Close() error

Close flushes and closes the encoder.

func (*Encoder) Encode

func (e *Encoder) Encode(v any) error

Encode writes v to the encoder's output.

func (*Encoder) SetIndent

func (e *Encoder) SetIndent(spaces int)

SetIndent sets the indentation level for the encoder.

type Node

type Node = yaml.Node

Node re-exports yaml.Node for packages that need node-based operations without importing yaml.v3 directly.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL