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

CVE-2017-15103

CVE-2017-15103

Description

A security-check flaw was found in the way the Heketi 5 server API handled user requests. An authenticated Heketi user could send specially crafted requests to the Heketi server, resulting in remote command execution as the user running Heketi server and possibly privilege escalation.

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.