Skip to content

Commit 3e5a527

Browse files
authored
Merge pull request from GHSA-9c5w-9q3f-3hv7
Signed-off-by: Juan Antonio Osorio <[email protected]>
1 parent ee05c7a commit 3e5a527

File tree

2 files changed

+84
-4
lines changed

2 files changed

+84
-4
lines changed

internal/controlplane/handlers_githubwebhooks_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ import (
2121
"database/sql"
2222
"encoding/json"
2323
"fmt"
24+
"io"
2425
"net/http"
2526
"os"
27+
"strings"
2628
"testing"
2729
"time"
2830

@@ -436,6 +438,73 @@ func (s *UnitTestSuite) TestNoopWebhookHandler() {
436438
assert.Equal(t, http.StatusOK, resp.StatusCode, "unexpected status code")
437439
}
438440

441+
func (s *UnitTestSuite) TestHandleWebHookWithTooLargeRequest() {
442+
t := s.T()
443+
t.Parallel()
444+
445+
ctrl := gomock.NewController(t)
446+
defer ctrl.Finish()
447+
448+
mockStore := mockdb.NewMockStore(ctrl)
449+
srv, evt := newDefaultServer(t, mockStore, nil)
450+
defer evt.Close()
451+
452+
pq := testqueue.NewPassthroughQueue(t)
453+
queued := pq.GetQueue()
454+
455+
evt.Register(events.TopicQueueEntityEvaluate, pq.Pass)
456+
457+
go func() {
458+
err := evt.Run(context.Background())
459+
require.NoError(t, err, "failed to run eventer")
460+
}()
461+
462+
<-evt.Running()
463+
464+
hook := withMaxSizeMiddleware(srv.HandleGitHubWebHook())
465+
port, err := rand.GetRandomPort()
466+
if err != nil {
467+
t.Fatal(err)
468+
}
469+
addr := fmt.Sprintf("localhost:%d", port)
470+
server := &http.Server{
471+
Addr: fmt.Sprintf(":%d", port),
472+
Handler: hook,
473+
ReadHeaderTimeout: 1 * time.Second,
474+
}
475+
go server.ListenAndServe()
476+
477+
event := github.PackageEvent{
478+
Action: github.String("published"),
479+
Repo: &github.Repository{
480+
ID: github.Int64(12345),
481+
Name: github.String("stacklok/minder"),
482+
},
483+
Org: &github.Organization{
484+
Login: github.String("stacklok"),
485+
},
486+
}
487+
packageJson, err := json.Marshal(event)
488+
require.NoError(t, err, "failed to marshal package event")
489+
490+
maliciousBody := strings.NewReader(strings.Repeat("1337", 1000000000))
491+
maliciousBodyReader := io.MultiReader(maliciousBody, maliciousBody, maliciousBody, maliciousBody, maliciousBody)
492+
_ = packageJson
493+
494+
client := &http.Client{}
495+
req, err := http.NewRequest("POST", fmt.Sprintf("http://%s", addr), maliciousBodyReader)
496+
require.NoError(t, err, "failed to create request")
497+
498+
req.Header.Add("X-GitHub-Event", "meta")
499+
req.Header.Add("X-GitHub-Delivery", "12345")
500+
req.Header.Add("Content-Type", "application/json")
501+
resp, err := httpDoWithRetry(client, req)
502+
require.NoError(t, err, "failed to make request")
503+
// We expect OK since we don't want to leak information about registered repositories
504+
require.Equal(t, http.StatusBadRequest, resp.StatusCode, "unexpected status code")
505+
assert.Len(t, queued, 0)
506+
}
507+
439508
func TestAll(t *testing.T) {
440509
t.Parallel()
441510

internal/controlplane/server.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ const metricsPath = "/metrics"
7070

7171
var (
7272
readHeaderTimeout = 2 * time.Second
73+
74+
// RequestBodyMaxBytes is the maximum number of bytes that can be read from a request body
75+
// We limit to 2MB for now
76+
RequestBodyMaxBytes int64 = 2 << 20
7377
)
7478

7579
// Server represents the controlplane server
@@ -316,10 +320,10 @@ func (s *Server) StartHTTPServer(ctx context.Context) error {
316320
return fmt.Errorf("failed to register GitHub App callback handler: %w", err)
317321
}
318322

319-
mux.Handle("/", s.handlerWithHTTPMiddleware(gwmux))
320-
mux.Handle("/api/v1/webhook/", mw(s.HandleGitHubWebHook()))
321-
mux.Handle("/api/v1/ghapp/", mw(s.HandleGitHubAppWebhook()))
322-
mux.Handle("/api/v1/gh-marketplace/", mw(s.NoopWebhookHandler()))
323+
mux.Handle("/", withMaxSizeMiddleware(s.handlerWithHTTPMiddleware(gwmux)))
324+
mux.Handle("/api/v1/webhook/", mw(withMaxSizeMiddleware(s.HandleGitHubWebHook())))
325+
mux.Handle("/api/v1/ghapp/", mw(withMaxSizeMiddleware(s.HandleGitHubAppWebhook())))
326+
mux.Handle("/api/v1/gh-marketplace/", mw(withMaxSizeMiddleware(s.NoopWebhookHandler())))
323327
mux.Handle("/static/", fs)
324328

325329
errch := make(chan error)
@@ -451,3 +455,10 @@ func shutdownHandler(component string, sdf shutdowner) {
451455
log.Fatal().Msgf("error shutting down '%s': %+v", component, err)
452456
}
453457
}
458+
459+
func withMaxSizeMiddleware(h http.Handler) http.Handler {
460+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
461+
r.Body = http.MaxBytesReader(w, r.Body, RequestBodyMaxBytes)
462+
h.ServeHTTP(w, r)
463+
})
464+
}

0 commit comments

Comments
 (0)