VYPR
High severityNVD Advisory· Published Mar 24, 2026· Updated Mar 25, 2026

Soft Serve: Authenticated repo import can clone server-local private repositories

CVE-2026-33353

Description

Soft Serve is a self-hostable Git server for the command line. From version 0.6.0 to before version 0.11.6, an authorization flaw in repo import allows any authenticated SSH user to clone a server-local Git repository, including another user's private repo, into a new repository they control. This issue has been patched in version 0.11.6.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/charmbracelet/soft-serveGo
>= 0.6.0, < 0.11.60.11.6

Affected products

1

Patches

1
c147421caf23

Merge commit from fork

https://github.com/charmbracelet/soft-serveEvan MORVANMar 19, 2026via ghsa
3 files changed · +50 0
  • pkg/backend/repo.go+14 0 modified
    @@ -25,6 +25,15 @@ import (
     	"github.com/charmbracelet/soft-serve/pkg/webhook"
     )
     
    +func validateImportRemote(remote string) error {
    +	endpoint, err := lfs.NewEndpoint(remote)
    +	if err != nil || endpoint.Host == "" {
    +		return proto.ErrInvalidRemote
    +	}
    +
    +	return nil
    +}
    +
     // CreateRepository creates a new repository.
     //
     // It implements backend.Backend.
    @@ -96,6 +105,11 @@ func (d *Backend) ImportRepository(_ context.Context, name string, user proto.Us
     		return nil, err
     	}
     
    +	remote = utils.Sanitize(remote)
    +	if err := validateImportRemote(remote); err != nil {
    +		return nil, err
    +	}
    +
     	rp := filepath.Join(d.repoPath(name))
     
     	tid := "import:" + name
    
  • pkg/proto/errors.go+2 0 modified
    @@ -7,6 +7,8 @@ import (
     var (
     	// ErrUnauthorized is returned when the user is not authorized to perform action.
     	ErrUnauthorized = errors.New("unauthorized")
    +	// ErrInvalidRemote is returned when a repository import remote is invalid.
    +	ErrInvalidRemote = errors.New("remote must be a network URL")
     	// ErrFileNotFound is returned when the file is not found.
     	ErrFileNotFound = errors.New("file not found")
     	// ErrRepoNotFound is returned when a repository is not found.
    
  • testscript/testdata/repo-import-local-path.txtar+34 0 added
    @@ -0,0 +1,34 @@
    +# vi: set ft=conf
    +
    +[windows] skip 'uses a raw server filesystem path as the import remote'
    +
    +# start soft serve
    +exec soft serve &
    +# wait for SSH server to start
    +ensureserverrunning SSH_PORT
    +
    +# create a private repo and a second user
    +soft repo create secret -p
    +soft user create user1 --key "$USER1_AUTHORIZED_KEY"
    +
    +# seed the private repo with content
    +git clone ssh://localhost:$SSH_PORT/secret secret
    +mkfile ./secret/SECRET.txt 'top secret'
    +git -C secret add -A
    +git -C secret commit -m 'first'
    +git -C secret push origin HEAD
    +
    +# user1 cannot read the private repo directly
    +! usoft repo info secret
    +stderr 'repository not found'
    +
    +# user1 also must not be able to import the server-local repo path
    +! usoft repo import stolen "$DATA_PATH/repos/secret.git" --lfs-endpoint http://example.com
    +stderr 'remote must be a network URL'
    +
    +# the failed import must not create a readable repo
    +! usoft repo info stolen
    +stderr 'repository not found'
    +
    +[windows] stopserver
    +[windows] ! stderr .
    

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

5

News mentions

0

No linked articles in our index yet.