XTLS/Xray-core · error · ErrPSKTooShort
PSK must be at least %d bytes
Error message
PSK must be at least %d bytes
What it means
NewSalamanderObfuscator (finalmask/salamander salting obfuscator) requires the pre-shared key to be at least smPSKMinLen = 4 bytes; shorter keys are rejected via the sentinel ErrPSKTooShort before any obfuscation state is built. The PSK seeds a BLAKE2b-256 key combined with a per-packet 8-byte random salt.
Source
Thrown at transport/internet/finalmask/salamander/salamander.go:18
package salamander
import (
"crypto/rand"
"fmt"
"sync"
"github.com/xtls/xray-core/common"
"golang.org/x/crypto/blake2b"
)
const (
smPSKMinLen = 4
smSaltLen = 8
smKeyLen = blake2b.Size256
)
var ErrPSKTooShort = fmt.Errorf("PSK must be at least %d bytes", smPSKMinLen)
// SalamanderObfuscator is an obfuscator that obfuscates each packet with
// the BLAKE2b-256 hash of a pre-shared key combined with a random salt.
// Packet format: [8-byte salt][payload]
type SalamanderObfuscator struct {
PSK []byte
lk sync.Mutex
keyInput []byte
}
func NewSalamanderObfuscator(psk []byte) (*SalamanderObfuscator, error) {
if len(psk) < smPSKMinLen {
return nil, ErrPSKTooShort
}
pskCopy := append([]byte(nil), psk...)
keyInput := make([]byte, len(pskCopy)+smSaltLen)
copy(keyInput, pskCopy)View on GitHub (pinned to 7d214f8b09)
Solutions
- Use a PSK of at least 4 bytes — in practice a long random secret (16-32 bytes)
- If the key is encoded, confirm the decode path produces the intended byte length before passing it in
- Keep the PSK identical on both peers; only its length/format matter for this check
- Compare errors.Is(err, salamander.ErrPSKTooShort) to give a precise config error message
Example fix
// before
ob, err := salamander.NewSalamanderObfuscator([]byte("ab"))
// after
ob, err := salamander.NewSalamanderObfuscator([]byte("at-least-4-bytes")) Defensive patterns
Strategy: validation
Validate before calling
import "errors"
func validSalamanderPSK(psk []byte) error {
if len(psk) < 4 {
return errors.New("salamander PSK too short: need >= 4 bytes")
}
return nil
}
// call before salamander.NewSalamanderObfuscator(psk) Try / catch
ob, err := salamander.NewSalamanderObfuscator(psk)
if err != nil {
if errors.Is(err, salamander.ErrPSKTooShort) {
return fmt.Errorf("config error: PSK must be >= 4 bytes, got %d", len(psk))
}
return err
} Prevention
- Use 16-32 byte random PSKs in practice
- Verify encoded-key decode length before passing bytes in
- Compare with errors.Is against the exported ErrPSKTooShort sentinel
When it happens
Trigger: Constructing a SalamanderObfuscator with a psk shorter than 4 bytes — e.g. a 1-3 character string converted to bytes, or a decoded key that came out empty/short (bad base64, wrong codec).
Common situations: Configuring the salamander obfuscation layer with a trivially short password; base64/hex decode of the configured key producing fewer bytes than expected due to encoding mismatches (padded vs raw, hex vs base64).
Related errors
- missing key
- not a Service.
- Dispatcher: Invalid destination.
- FakeDNSEngine is not initialized, but such a sniffer is used
- Failed to convert address to Net IP.
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/ac2c3c473dd536db.
Report an issue: GitHub.