VYPR
High severity7.8NVD Advisory· Published Dec 18, 2017· Updated May 13, 2026

CVE-2017-15104

CVE-2017-15104

Description

An access flaw was found in Heketi 5, where the heketi.json configuration file was world readable. An attacker having local access to the Heketi server could read plain-text passwords from the heketi.json file.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/heketi/heketiGo
< 5.0.15.0.1

Affected products

1

Patches

1
787bae461b23

api: input validation

https://github.com/heketi/heketiRaghavendra TalurDec 18, 2017via ghsa
7 files changed · +171 4
  • apps/glusterfs/app_device.go+13 0 modified
    @@ -28,6 +28,13 @@ func (a *App) DeviceAdd(w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    +	err = msg.Validate()
    +	if err != nil {
    +		http.Error(w, "validation failed: "+err.Error(), http.StatusBadRequest)
    +		logger.LogError("validation failed: " + err.Error())
    +		return
    +	}
    +
     	// Check the message has devices
     	if msg.Name == "" {
     		http.Error(w, "no devices added", http.StatusBadRequest)
    @@ -323,6 +330,12 @@ func (a *App) DeviceSetState(w http.ResponseWriter, r *http.Request) {
     		http.Error(w, "request unable to be parsed", 422)
     		return
     	}
    +	err = msg.Validate()
    +	if err != nil {
    +		http.Error(w, "validation failed: "+err.Error(), http.StatusBadRequest)
    +		logger.LogError("validation failed: " + err.Error())
    +		return
    +	}
     
     	// Check for valid id, return immediately if not valid
     	err = a.db.View(func(tx *bolt.Tx) error {
    
  • apps/glusterfs/app_node.go+13 0 modified
    @@ -28,6 +28,13 @@ func (a *App) NodeAdd(w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    +	err = msg.Validate()
    +	if err != nil {
    +		http.Error(w, "validation failed: "+err.Error(), http.StatusBadRequest)
    +		logger.LogError("validation failed: " + err.Error())
    +		return
    +	}
    +
     	// Check information in JSON request
     	if len(msg.Hostnames.Manage) == 0 {
     		http.Error(w, "Manage hostname missing", http.StatusBadRequest)
    @@ -330,6 +337,12 @@ func (a *App) NodeSetState(w http.ResponseWriter, r *http.Request) {
     		http.Error(w, "request unable to be parsed", 422)
     		return
     	}
    +	err = msg.Validate()
    +	if err != nil {
    +		http.Error(w, "validation failed: "+err.Error(), http.StatusBadRequest)
    +		logger.LogError("validation failed: " + err.Error())
    +		return
    +	}
     
     	// Check state is supported
     	err = a.db.View(func(tx *bolt.Tx) error {
    
  • apps/glusterfs/app_volume.go+12 0 modified
    @@ -34,6 +34,12 @@ func (a *App) VolumeCreate(w http.ResponseWriter, r *http.Request) {
     		http.Error(w, "request unable to be parsed", 422)
     		return
     	}
    +	err = msg.Validate()
    +	if err != nil {
    +		http.Error(w, "validation failed: "+err.Error(), http.StatusBadRequest)
    +		logger.LogError("validation failed: " + err.Error())
    +		return
    +	}
     
     	switch {
     	case msg.Gid < 0:
    @@ -287,6 +293,12 @@ func (a *App) VolumeExpand(w http.ResponseWriter, r *http.Request) {
     		return
     	}
     	logger.Debug("Msg: %v", msg)
    +	err = msg.Validate()
    +	if err != nil {
    +		http.Error(w, "validation failed: "+err.Error(), http.StatusBadRequest)
    +		logger.LogError("validation failed: " + err.Error())
    +		return
    +	}
     
     	if msg.Size < 1 {
     		http.Error(w, "Invalid volume size", http.StatusBadRequest)
    
  • executors/sshexec/device.go+2 2 modified
    @@ -33,7 +33,7 @@ func (s *SshExecutor) DeviceSetup(host, device, vgid string) (d *executors.Devic
     
     	// Setup commands
     	commands := []string{
    -		fmt.Sprintf("pvcreate --metadatasize=128M --dataalignment=256K %v", device),
    +		fmt.Sprintf("pvcreate --metadatasize=128M --dataalignment=256K '%v'", device),
     		fmt.Sprintf("vgcreate %v %v", s.vgName(vgid), device),
     	}
     
    @@ -65,7 +65,7 @@ func (s *SshExecutor) DeviceTeardown(host, device, vgid string) error {
     	// Setup commands
     	commands := []string{
     		fmt.Sprintf("vgremove %v", s.vgName(vgid)),
    -		fmt.Sprintf("pvremove %v", device),
    +		fmt.Sprintf("pvremove '%v'", device),
     	}
     
     	// Execute command
    
  • glide.lock+8 2 modified
    @@ -1,6 +1,8 @@
    -hash: 59834cf573ea7a48f90686852f6c02428d2ffee8ecfcfeafac4ca2e52638f00a
    -updated: 2017-05-22T14:00:49.364236742-04:00
    +hash: 5fc263bfacc703e0a599166ccae968891dd53d7b4e42a3d8356b3194e45833bb
    +updated: 2017-12-18T17:52:34.69084539+05:30
     imports:
    +- name: github.com/asaskevich/govalidator
    +  version: 852d82c746b23d9b357b210ea470d99f4e023b72
     - name: github.com/auth0/go-jwt-middleware
       version: f3f7de3b9e394e3af3b88e1b9457f6f71d1ae0ac
     - name: github.com/Azure/go-ansiterm
    @@ -53,6 +55,10 @@ imports:
       version: 6aced65f8501fe1217321abf0749d354824ba2ff
     - name: github.com/go-openapi/swag
       version: 1d0bd113de87027671077d3c71eb3ac5d7dbba72
    +- name: github.com/go-ozzo/ozzo-validation
    +  version: 85dcd8368eba387e65a03488b003e233994e87e9
    +  subpackages:
    +  - is
     - name: github.com/gogo/protobuf
       version: e18d7aa8f8c624c915db340349aad4c49b10d173
       subpackages:
    
  • glide.yaml+2 0 modified
    @@ -22,3 +22,5 @@ import:
       - ssh/agent
     - package: k8s.io/client-go
       version: v3.0.0-beta.0
    +- package: github.com/go-ozzo/ozzo-validation
    +  version: v3.3
    
  • pkg/glusterfs/api/types.go+121 0 modified
    @@ -18,9 +18,36 @@ package api
     
     import (
     	"fmt"
    +	"regexp"
     	"sort"
    +
    +	"github.com/go-ozzo/ozzo-validation"
    +	"github.com/go-ozzo/ozzo-validation/is"
    +)
    +
    +var (
    +	// Restricting the deviceName to much smaller subset of Unix Path
    +	// as unix path takes almost everything except NULL
    +	deviceNameRe = regexp.MustCompile("^/[a-zA-Z0-9_./-]+$")
    +
    +	// Volume name constraints decided by looking at
    +	// "cli_validate_volname" function in cli-cmd-parser.c of gluster code
    +	volumeNameRe = regexp.MustCompile("^[a-zA-Z0-9_-]+$")
    +
    +	blockVolNameRe = regexp.MustCompile("^[a-zA-Z0-9_-]+$")
     )
     
    +// ValidateUUID is written this way because heketi UUID does not
    +// conform to neither UUID v4 nor v5.
    +func ValidateUUID(value interface{}) error {
    +	s, _ := value.(string)
    +	err := validation.Validate(s, validation.RuneLength(32, 32), is.Hexadecimal)
    +	if err != nil {
    +		return fmt.Errorf("not a valid UUID")
    +	}
    +	return nil
    +}
    +
     // State
     type EntryState string
     
    @@ -31,6 +58,15 @@ const (
     	EntryStateFailed  EntryState = "failed"
     )
     
    +func ValidateEntryState(value interface{}) error {
    +	s, _ := value.(string)
    +	err := validation.Validate(s, validation.Required, validation.In(EntryStateOnline, EntryStateOffline, EntryStateFailed))
    +	if err != nil {
    +		return fmt.Errorf("state requested is not valid")
    +	}
    +	return nil
    +}
    +
     type DurabilityType string
     
     const (
    @@ -39,11 +75,26 @@ const (
     	DurabilityEC             DurabilityType = "disperse"
     )
     
    +func ValidateDurabilityType(value interface{}) error {
    +	s, _ := value.(string)
    +	err := validation.Validate(s, validation.Required, validation.In(DurabilityReplicate, DurabilityDistributeOnly, DurabilityEC))
    +	if err != nil {
    +		return fmt.Errorf("durability type requested is not valid")
    +	}
    +	return nil
    +}
    +
     // Common
     type StateRequest struct {
     	State EntryState `json:"state"`
     }
     
    +func (statereq StateRequest) Validate() error {
    +	return validation.ValidateStruct(&statereq,
    +		validation.Field(&statereq.State, validation.Required, validation.By(ValidateEntryState)),
    +	)
    +}
    +
     // Storage values in KB
     type StorageSize struct {
     	Total uint64 `json:"total"`
    @@ -56,6 +107,35 @@ type HostAddresses struct {
     	Storage sort.StringSlice `json:"storage"`
     }
     
    +func ValidateManagementHostname(value interface{}) error {
    +	s, _ := value.(sort.StringSlice)
    +	for _, fqdn := range s {
    +		err := validation.Validate(fqdn, validation.Required, is.Host)
    +		if err != nil {
    +			return fmt.Errorf("Manage hostname should be valid hostname")
    +		}
    +	}
    +	return nil
    +}
    +
    +func ValidateStorageHostname(value interface{}) error {
    +	s, _ := value.(sort.StringSlice)
    +	for _, ip := range s {
    +		err := validation.Validate(ip, validation.Required, is.Host)
    +		if err != nil {
    +			return fmt.Errorf("Storage hostname should be valid IP")
    +		}
    +	}
    +	return nil
    +}
    +
    +func (hostadd HostAddresses) Validate() error {
    +	return validation.ValidateStruct(&hostadd,
    +		validation.Field(&hostadd.Manage, validation.Required, validation.By(ValidateManagementHostname)),
    +		validation.Field(&hostadd.Storage, validation.Required, validation.By(ValidateStorageHostname)),
    +	)
    +}
    +
     // Brick
     type BrickInfo struct {
     	Id       string `json:"id"`
    @@ -73,11 +153,24 @@ type Device struct {
     	Name string `json:"name"`
     }
     
    +func (dev Device) Validate() error {
    +	return validation.ValidateStruct(&dev,
    +		validation.Field(&dev.Name, validation.Required, validation.Match(deviceNameRe)),
    +	)
    +}
    +
     type DeviceAddRequest struct {
     	Device
     	NodeId string `json:"node"`
     }
     
    +func (devAddReq DeviceAddRequest) Validate() error {
    +	return validation.ValidateStruct(&devAddReq,
    +		validation.Field(&devAddReq.Device, validation.Required),
    +		validation.Field(&devAddReq.NodeId, validation.Required, validation.By(ValidateUUID)),
    +	)
    +}
    +
     type DeviceInfo struct {
     	Device
     	Storage StorageSize `json:"storage"`
    @@ -97,6 +190,14 @@ type NodeAddRequest struct {
     	ClusterId string        `json:"cluster"`
     }
     
    +func (req NodeAddRequest) Validate() error {
    +	return validation.ValidateStruct(&req,
    +		validation.Field(&req.Zone, validation.Required, validation.Min(1)),
    +		validation.Field(&req.Hostnames, validation.Required),
    +		validation.Field(&req.ClusterId, validation.Required, validation.By(ValidateUUID)),
    +	)
    +}
    +
     type NodeInfo struct {
     	NodeAddRequest
     	Id string `json:"id"`
    @@ -160,6 +261,20 @@ type VolumeCreateRequest struct {
     	} `json:"snapshot"`
     }
     
    +func (volCreateRequest VolumeCreateRequest) Validate() error {
    +	return validation.ValidateStruct(&volCreateRequest,
    +		validation.Field(&volCreateRequest.Size, validation.Required, validation.Min(1)),
    +		validation.Field(&volCreateRequest.Clusters, validation.By(ValidateUUID)),
    +		validation.Field(&volCreateRequest.Name, validation.Match(volumeNameRe)),
    +		validation.Field(&volCreateRequest.Durability, validation.Skip),
    +		validation.Field(&volCreateRequest.Gid, validation.Skip),
    +		validation.Field(&volCreateRequest.GlusterVolumeOptions, validation.Skip),
    +		// This is possibly a bug in validation lib, ignore next two lines for now
    +		// validation.Field(&volCreateRequest.Snapshot.Enable, validation.In(true, false)),
    +		// validation.Field(&volCreateRequest.Snapshot.Factor, validation.Min(1.0)),
    +	)
    +}
    +
     type VolumeInfo struct {
     	VolumeCreateRequest
     	Id      string `json:"id"`
    @@ -186,6 +301,12 @@ type VolumeExpandRequest struct {
     	Size int `json:"expand_size"`
     }
     
    +func (volExpandReq VolumeExpandRequest) Validate() error {
    +	return validation.ValidateStruct(&volExpandReq,
    +		validation.Field(&volExpandReq.Size, validation.Required, validation.Min(1)),
    +	)
    +}
    +
     // Constructors
     
     func NewVolumeInfoResponse() *VolumeInfoResponse {
    

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.