Repository: lestrrat-go/jwx
Pull request #853 (2022-11-25 00:44:48)

merge develop/v2 to v2

codecov-commenter: # [Codecov](https://codecov.io/gh/lestrrat-go/jwx/pull/853?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) Report
> Merging [#853](https://codecov.io/gh/lestrrat-go/jwx/pull/853?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) (f64b7ab) into [v2](https://codecov.io/gh/lestrrat-go/jwx/commit/43ca1406d71955b098e833da5fc170ddef88e51a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) (43ca140) will **decrease** coverage by `0.52%`.
> The diff coverage is `72.88%`.

```diff
@@            Coverage Diff             @@
##               v2     #853      +/-   ##
==========================================
- Coverage   71.78%   71.26%   -0.53%     
==========================================
  Files          90       92       +2     
  Lines        9662    13255    +3593     
==========================================
+ Hits         6936     9446    +2510     
- Misses       1928     2994    +1066     
- Partials      798      815      +17     
```


| [Impacted Files](https://codecov.io/gh/lestrrat-go/jwx/pull/853?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) | Coverage Δ | |
|---|---|---|
| [formatkind\_string\_gen.go](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-Zm9ybWF0a2luZF9zdHJpbmdfZ2VuLmdv) | `100.00% <ø> (ø)` | |
| [internal/json/goccy.go](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-aW50ZXJuYWwvanNvbi9nb2NjeS5nbw==) | `100.00% <ø> (ø)` | |
| [jwa/elliptic\_gen.go](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andhL2VsbGlwdGljX2dlbi5nbw==) | `100.00% <ø> (ø)` | |
| [jwa/secp2561k.go](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andhL3NlY3AyNTYxay5nbw==) | `100.00% <ø> (ø)` | |
| [jwe/compress.go](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andlL2NvbXByZXNzLmdv) | `0.00% <0.00%> (ø)` | |
| [jwe/decrypt.go](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andlL2RlY3J5cHQuZ28=) | `58.51% <ø> (-0.95%)` | :arrow_down: |
| [jwe/internal/cipher/cipher.go](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andlL2ludGVybmFsL2NpcGhlci9jaXBoZXIuZ28=) | `62.06% <0.00%> (+1.67%)` | :arrow_up: |
| [jwk/es256k.go](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andrL2VzMjU2ay5nbw==) | `100.00% <ø> (ø)` | |
| [jwk/fetch.go](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andrL2ZldGNoLmdv) | `73.52% <ø> (+0.45%)` | :arrow_up: |
| [jws/es256k.go](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andzL2VzMjU2ay5nbw==) | `100.00% <ø> (ø)` | |
| ... and [136 more](https://codecov.io/gh/lestrrat-go/jwx/pull/853/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go)


Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 3ded2b1a..96bc6b46 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -15,3 +15,8 @@ updates:
     schedule:
       interval: "daily"
     target-branch: "develop/v1"
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "daily"
+    target-branch: "develop/v2"
diff --git a/.github/workflows/assign-pr.yml b/.github/workflows/assign-pr.yml
index 92b75a63..8c8b4504 100644
--- a/.github/workflows/assign-pr.yml
+++ b/.github/workflows/assign-pr.yml
@@ -7,6 +7,6 @@ jobs:
   add-reviews:
     runs-on: ubuntu-latest
     steps:
-      - uses: kentaro-m/auto-assign-action@v1.2.0
+      - uses: kentaro-m/auto-assign-action@v1.2.4
         with:
           configuration-path: .github/auto-assign-pr.yml
diff --git a/.github/workflows/autodoc.yml b/.github/workflows/autodoc.yml
index 7b2ab76d..6460d1e5 100644
--- a/.github/workflows/autodoc.yml
+++ b/.github/workflows/autodoc.yml
@@ -13,7 +13,7 @@ jobs:
     if: github.event.pull_request.merged == true
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
       - name: Process markdown files
         run: |
           find . -name '*.md' | xargs perl tools/autodoc.pl
diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index 98f6d12d..c3e75eaa 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -13,9 +13,9 @@ jobs:
     name: "Test [ Go ${{ matrix.go }} / JSON Backend ${{ matrix.json_backend }} ]"
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
       - name: Cache Go modules
-        uses: actions/cache@v2
+        uses: actions/cache@v3
         with:
           path: |
             ~/go/pkg/mod
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index cb505129..515f2faf 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,14 +10,14 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        go_tags: [ 'stdlib', 'goccy', 'es256k', 'all']
+        go_tags: [ 'stdlib', 'goccy', 'es256k', 'alltags']
         go: [ '1.19', '1.18', '1.17' ]
     name: "Test [ Go ${{ matrix.go }} / Tags ${{ matrix.go_tags }} ]"
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
       - name: Cache Go modules
-        uses: actions/cache@v2
+        uses: actions/cache@v3
         with:
           path: |
             ~/go/pkg/mod
@@ -42,6 +42,8 @@ jobs:
           echo "::add-path::$(go env GOPATH)/bin"
       - name: Install stringer
         run: go install golang.org/x/tools/cmd/stringer@latest
+      - name: Install tparse
+        run: go install github.com/mfridman/tparse@latest
       - name: Install jose
         run: sudo apt-get install -y --no-install-recommends jose
       - run: make generate
@@ -51,7 +53,7 @@ jobs:
         run: make cover-${{ matrix.go_tags }}
       - name: Upload code coverage to codecov
         if: matrix.go == '1.19'
-        uses: codecov/codecov-action@v1
+        uses: codecov/codecov-action@v3
         with:
           file: ./coverage.out
       - name: Check difference between generation code and commit code
diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml
index a2593da7..0598734e 100644
--- a/.github/workflows/smoke.yml
+++ b/.github/workflows/smoke.yml
@@ -13,17 +13,17 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        go_tags: [ 'stdlib', 'goccy', 'es256k', 'all' ]
+        go_tags: [ 'stdlib', 'goccy', 'es256k', 'alltags' ]
         go: [ '1.19', '1.18', '1.17' ]
     name: "Smoke [ Go ${{ matrix.go }} / Tags ${{ matrix.go_tags }} ]"
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
       - name: Check documentation generator
         run: |
           find . -name '*.md' | xargs env AUTODOC_DRYRUN=1 perl tools/autodoc.pl
       - name: Cache Go modules
-        uses: actions/cache@v2
+        uses: actions/cache@v3
         with:
           path: |
             ~/go/pkg/mod
@@ -38,6 +38,8 @@ jobs:
           check-latest: true
       - name: Install stringer
         run: go install golang.org/x/tools/cmd/stringer@latest
+      - name: Install tparse
+        run: go install github.com/mfridman/tparse@latest
       - name: Install jose
         run: sudo apt-get install -y --no-install-recommends jose
       - run: make generate
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index 105fd29f..e52aff75 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -7,7 +7,7 @@ jobs:
   stale:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/stale@v4
+      - uses: actions/stale@v6
         with:
           stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
           stale-pr-message: 'This PR is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 14 days.'
diff --git a/Changes b/Changes
index 332a4ce3..f68a2efc 100644
--- a/Changes
+++ b/Changes
@@ -4,6 +4,23 @@ Changes
 v2 has many incompatibilities with v1. To see the full list of differences between
 v1 and v2, please read the Changes-v2.md file (https://github.com/lestrrat-go/jwx/blob/develop/v2/Changes-v2.md)
 
+v2.0.8 - 25 Nov 2022
+[Security Fixes]
+  * [jws][jwe] Starting from go 1.19, code related to elliptic algorithms
+    panics (instead of returning an error) when certain methods
+    such as `ScalarMult` are called using points that are not on the
+    elliptic curve being used.
+
+    Using inputs that cause this condition, and you accept unverified JWK
+    from the outside it may be possible for a third-party to cause panics
+    in your program.
+
+    This has been fixed by verifying that the point being used is actually
+    on the curve before such computations (#840)
+[Miscellaneous]
+  * `jwx.GuessFormat` now returns `jwx.InvalidFormat` when the heuristics
+    is sure that the buffer format is invalid.
+
 v2.0.7 - 15 Nov 2022
 [New features]
   * [jwt] Each `jwt.Token` now has an `Options()` method
diff --git a/Makefile b/Makefile
index 4b548b7e..f3247b25 100644
--- a/Makefile
+++ b/Makefile
@@ -11,58 +11,58 @@ realclean:
 	rm coverage.out
 
 test-cmd:
-	go test -v -race $(TESTOPTS)
+	env TESTOPTS="$(TESTOPTS)" ./tools/test.sh
 
 test:
-	$(MAKE) TESTOPTS=./... test-cmd
-	$(MAKE) -f $(PWD)/Makefile -C examples test-cmd
-	$(MAKE) -f $(PWD)/Makefile -C bench/performance test-cmd
+	$(MAKE) test-stdlib TESTOPTS=
+
+test-stdlib:
+	$(MAKE) test-cmd TESTOPTS=
+
+test-goccy:
+	$(MAKE) test-cmd TESTOPTS="-tags jwx_goccy"
+
+test-es256k:
+	$(MAKE) test-cmd TESTOPTS="-tags jwx_es256k"
+
+test-alltags:
+	$(MAKE) test-cmd TESTOPTS="-tags jwx_goccy,jwx_es256k"
 
 cover-cmd:
-	$(MAKE) test-cmd 
-	$(MAKE) -f $(PWD)/Makefile -C examples TESTOPTS= test-cmd
-	$(MAKE) -f $(PWD)/Makefile -C bench/performance TESTOPTS= test-cmd
-	$(MAKE) -f $(PWD)/Makefile -C cmd/jwx TESTOPTS= test-cmd
-	@# This is NOT cheating. tools to generate code, and tools to
-	@# run tests don't need to be included in the final result.
-	@cat coverage.out.tmp | grep -v "internal/jose" | grep -v "internal/jwxtest" | grep -v "internal/cmd" > coverage.out
-	@rm coverage.out.tmp
+	env MODE=cover ./tools/test.sh
 
 cover:
 	$(MAKE) cover-stdlib
 
 cover-stdlib:
-	$(MAKE) cover-cmd TESTOPTS="-coverpkg=./... -coverprofile=coverage.out.tmp ./..."
+	$(MAKE) cover-cmd TESTOPTS=
 
 cover-goccy:
-	$(MAKE) cover-cmd TESTOPTS="-tags jwx_goccy -coverpkg=./... -coverprofile=coverage.out.tmp ./..."
+	$(MAKE) cover-cmd TESTOPTS="-tags jwx_goccy"
 
 cover-es256k:
-	$(MAKE) cover-cmd TESTOPTS="-tags jwx_es256k -coverpkg=./... -coverprofile=coverage.out.tmp ./..."
+	$(MAKE) cover-cmd TESTOPTS="-tags jwx_es256k"
 
-cover-all:
-	$(MAKE) cover-cmd TESTOPTS="-tags jwx_goccy,jwx_es256k -coverpkg=./... -coverprofile=coverage.out.tmp ./..."
+cover-alltags:
+	$(MAKE) cover-cmd TESTOPTS="-tags jwx_goccy,jwx_es256k"
 
 smoke-cmd:
-	$(MAKE) test-cmd
-	$(MAKE) -f $(PWD)/Makefile -C examples test-cmd
-	$(MAKE) -f $(PWD)/Makefile -C bench/performance test-cmd
-	$(MAKE) -f $(PWD)/Makefile -C cmd/jwx test-cmd
+	env MODE=short ./tools/test.sh
 
 smoke:
 	$(MAKE) smoke-stdlib
 
 smoke-stdlib:
-	$(MAKE) smoke-cmd TESTOPTS="-short ./..."
+	$(MAKE) smoke-cmd TESTOPTS=
 
 smoke-goccy:
-	$(MAKE) smoke-cmd TESTOPTS="-short -tags jwx_goccy ./..."
+	$(MAKE) smoke-cmd TESTOPTS="-tags jwx_goccy"
 
 smoke-es256k:
-	$(MAKE) smoke-cmd TESTOPTS="-short -tags jwx_es256k ./..."
+	$(MAKE) smoke-cmd TESTOPTS="-tags jwx_es256k"
 
-smoke-all:
-	$(MAKE) smoke-cmd TESTOPTS="-short -tags jwx_goccy,jwx_es256k ./..."
+smoke-alltags:
+	$(MAKE) smoke-cmd TESTOPTS="-tags jwx_goccy,jwx_es256k"
 
 viewcover:
 	go tool cover -html=coverage.out
diff --git a/bench/performance/go.mod b/bench/performance/go.mod
index b18c93cb..f6f2d104 100644
--- a/bench/performance/go.mod
+++ b/bench/performance/go.mod
@@ -2,4 +2,4 @@ module github.com/lestrrat-go/jwx/v2/bench/performance
 
 go 1.16
 
-require github.com/lestrrat-go/jwx/v2 v2.0.6
+require github.com/lestrrat-go/jwx/v2 v2.0.7
diff --git a/bench/performance/go.sum b/bench/performance/go.sum
index f3a6bc9e..6e90c20b 100644
--- a/bench/performance/go.sum
+++ b/bench/performance/go.sum
@@ -14,18 +14,20 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG
 github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
 github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
 github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
-github.com/lestrrat-go/jwx/v2 v2.0.6 h1:RlyYNLV892Ed7+FTfj1ROoF6x7WxL965PGTHso/60G0=
-github.com/lestrrat-go/jwx/v2 v2.0.6/go.mod h1:aVrGuwEr3cp2Prw6TtQvr8sQxe+84gruID5C9TxT64Q=
+github.com/lestrrat-go/jwx/v2 v2.0.7 h1:vNh7cA5pKS/1muWYpM1GeUHBCf/r1UFxYN60iv7LFRA=
+github.com/lestrrat-go/jwx/v2 v2.0.7/go.mod h1:zLxnyv9rTlEvOUHbc48FAfIL8iYu2hHvIRaTFGc8mT0=
 github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
 github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
diff --git a/cmd/jwx/go.mod b/cmd/jwx/go.mod
index 999852a9..c621fb42 100644
--- a/cmd/jwx/go.mod
+++ b/cmd/jwx/go.mod
@@ -3,7 +3,7 @@ module github.com/lestrrat-go/jwx/v2/cmd/jwx
 go 1.17
 
 require (
-	github.com/lestrrat-go/jwx/v2 v2.0.6
+	github.com/lestrrat-go/jwx/v2 v2.0.7
 	github.com/urfave/cli/v2 v2.3.0
 	golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f
 )
diff --git a/cmd/jwx/go.sum b/cmd/jwx/go.sum
index f0a5f1e0..751f5525 100644
--- a/cmd/jwx/go.sum
+++ b/cmd/jwx/go.sum
@@ -18,8 +18,8 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG
 github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
 github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
 github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
-github.com/lestrrat-go/jwx/v2 v2.0.6 h1:RlyYNLV892Ed7+FTfj1ROoF6x7WxL965PGTHso/60G0=
-github.com/lestrrat-go/jwx/v2 v2.0.6/go.mod h1:aVrGuwEr3cp2Prw6TtQvr8sQxe+84gruID5C9TxT64Q=
+github.com/lestrrat-go/jwx/v2 v2.0.7 h1:vNh7cA5pKS/1muWYpM1GeUHBCf/r1UFxYN60iv7LFRA=
+github.com/lestrrat-go/jwx/v2 v2.0.7/go.mod h1:zLxnyv9rTlEvOUHbc48FAfIL8iYu2hHvIRaTFGc8mT0=
 github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
 github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -30,10 +30,12 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
diff --git a/docs/00-anatomy.md b/docs/00-anatomy.md
index a3092802..a799de43 100644
--- a/docs/00-anatomy.md
+++ b/docs/00-anatomy.md
@@ -50,6 +50,16 @@ The signed content can be encoded in two different formats. The most common one
 eyJhbGciOiJFUzI1NiJ9.SGVsbG8sIFdvcmxkCg.3q5N5JyFphiJolUZuBuUZhuWDfmLDR__rZe3lnuaxWe3bfrfvJS9HmUUhie56NqkyN7vjOl8hm6tzJKTc2oNsg
 ```
 
+Please note that a JWS message may take three forms: compact, full JSON, and flattened JSON serialization.
+
+```mermaid
+graph TD
+    RawData[Raw Data] --> |"three base64 encoded segments,<br/> concatenated with ."| Compact[Compact Serialization]
+    RawData --> | JSON | JSON[JSON Serialization]
+    JSON --> |"does NOT have'signature'"| FullJSON[Full JSON Serialization]
+    JSON --> |"has 'signature'"| Flat[Flattened JSON Serialization]
+```
+
 JWS is implemented in github.com/lestrrat-go/jwx/v2/jws package. This package provides ways to sign arbitrary payload into JWS message, and ways to verify them.
 
 ## Documentation for `github.com/lestrrat-go/jwx/v2/jws`
diff --git a/docs/01-jwt.md b/docs/01-jwt.md
index 0ba4725d..67867071 100644
--- a/docs/01-jwt.md
+++ b/docs/01-jwt.md
@@ -1159,9 +1159,14 @@ source: [examples/jwt_flatten_audience_example_test.go](https://github.com/lestr
 
 ## Access JWS headers
 
-Note: If you are considering using JWS header fields to decide on which key to use for verification, consider [using a `jwt.KeyProvider`](#parse-and-verify-a-jwt-using-arbitrary-keys).
+The RFC defines JWS as an envelope to JWT (JWS can carry any payload, you just happened to assign a JWT to it). A JWT is just a bag of arbitrary key/value pairs, where some of them are predefined for validation. This means that JWS headers are NOT part of a JWT -- and thus you will not be able to access them through the `jwt.Token` itself.
 
-In order to access JWS headers such as `kid`, `alg`, etc, Please [look at the JWS documentation for it](./02-jws.md#parse-a-jws-message-and-access-jws-headers).
+If you need to access these JWS headers while parsing JWS signed JWT, you will need to reach into the tools defined in the `jws` package.
+
+* If you are considering using JWS header fields to decide on which key to use for verification, consider [using a `jwt.KeyProvider`](#parse-and-verify-a-jwt-using-arbitrary-keys).
+* If you are looking for ways to 
+
+Please [look at the JWS documentation for it](./02-jws.md#parse-a-jws-message-and-access-jws-headers) .
 
 ## Get/Set fields
 
diff --git a/examples/go.mod b/examples/go.mod
index 71ba74f8..56f87cfb 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -4,9 +4,7 @@ go 1.16
 
 require (
 	github.com/cloudflare/circl v1.1.0
-	github.com/lestrrat-go/jwx/v2 v2.0.6
+	github.com/lestrrat-go/jwx/v2 v2.0.7
 )
 
 replace github.com/cloudflare/circl v1.0.0 => github.com/cloudflare/circl v1.0.1-0.20210104183656-96a0695de3c3
-
-replace github.com/lestrrat-go/jwx/v2 => ../
diff --git a/examples/go.sum b/examples/go.sum
index 8b303e7e..234174f9 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -17,6 +17,8 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG
 github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
 github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
 github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
+github.com/lestrrat-go/jwx/v2 v2.0.7 h1:vNh7cA5pKS/1muWYpM1GeUHBCf/r1UFxYN60iv7LFRA=
+github.com/lestrrat-go/jwx/v2 v2.0.7/go.mod h1:zLxnyv9rTlEvOUHbc48FAfIL8iYu2hHvIRaTFGc8mT0=
 github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
 github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
diff --git a/format.go b/format.go
index 9662cea3..ba721aca 100644
--- a/format.go
+++ b/format.go
@@ -7,8 +7,15 @@ import (
 
 type FormatKind int
 
+// These constants describe the result from guessing the format
+// of the incoming buffer.
 const (
-	UnknownFormat FormatKind = iota
+	// InvalidFormat is returned when the format of the incoming buffer
+	// has been deemed conclusively invalid
+	InvalidFormat FormatKind = iota
+	// UnknownFormat is returned when GuessFormat was not able to conclusively
+	// determine the format of the
+	UnknownFormat
 	JWE
 	JWS
 	JWK
@@ -66,7 +73,7 @@ func GuessFormat(payload []byte) FormatKind {
 		case 4:
 			return JWE
 		default:
-			return UnknownFormat
+			return InvalidFormat
 		}
 	}
 
diff --git a/formatkind_string_gen.go b/formatkind_string_gen.go
index c2488655..38abd1bc 100644
--- a/formatkind_string_gen.go
+++ b/formatkind_string_gen.go
@@ -8,17 +8,18 @@ func _() {
 	// An "invalid array index" compiler error signifies that the constant values have changed.
 	// Re-run the stringer command to generate them again.
 	var x [1]struct{}
-	_ = x[UnknownFormat-0]
-	_ = x[JWE-1]
-	_ = x[JWS-2]
-	_ = x[JWK-3]
-	_ = x[JWKS-4]
-	_ = x[JWT-5]
+	_ = x[InvalidFormat-0]
+	_ = x[UnknownFormat-1]
+	_ = x[JWE-2]
+	_ = x[JWS-3]
+	_ = x[JWK-4]
+	_ = x[JWKS-5]
+	_ = x[JWT-6]
 }
 
-const _FormatKind_name = "UnknownFormatJWEJWSJWKJWKSJWT"
+const _FormatKind_name = "InvalidFormatUnknownFormatJWEJWSJWKJWKSJWT"
 
-var _FormatKind_index = [...]uint8{0, 13, 16, 19, 22, 26, 29}
+var _FormatKind_index = [...]uint8{0, 13, 26, 29, 32, 35, 39, 42}
 
 func (i FormatKind) String() string {
 	if i < 0 || i >= FormatKind(len(_FormatKind_index)-1) {
diff --git a/jwe/internal/keygen/keygen.go b/jwe/internal/keygen/keygen.go
index bab6041a..0d9c7ece 100644
--- a/jwe/internal/keygen/keygen.go
+++ b/jwe/internal/keygen/keygen.go
@@ -88,6 +88,9 @@ func (g Ecdhes) Generate() (ByteSource, error) {
 	pubinfo := make([]byte, 4)
 	binary.BigEndian.PutUint32(pubinfo, uint32(g.keysize)*8)
 
+	if !priv.PublicKey.Curve.IsOnCurve(g.pubkey.X, g.pubkey.Y) {
+		return nil, fmt.Errorf(`public key used does not contain a point (X,Y) on the curve`)
+	}
 	z, _ := priv.PublicKey.Curve.ScalarMult(g.pubkey.X, g.pubkey.Y, priv.D.Bytes())
 	zBytes := ecutil.AllocECPointBuffer(z, priv.PublicKey.Curve)
 	defer ecutil.ReleaseECPointBuffer(zBytes)
diff --git a/jws/ecdsa.go b/jws/ecdsa.go
index aadb0594..a2d644e4 100644
--- a/jws/ecdsa.go
+++ b/jws/ecdsa.go
@@ -172,6 +172,10 @@ func (v *ecdsaVerifier) Verify(payload []byte, signature []byte, key interface{}
 		}
 	}
 
+	if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) {
+		return fmt.Errorf(`public key used does not contain a point (X,Y) on the curve`)
+	}
+
 	r := pool.GetBigInt()
 	s := pool.GetBigInt()
 	defer pool.ReleaseBigInt(r)
diff --git a/jwt/jwt.go b/jwt/jwt.go
index bd8e5206..cd059a26 100644
--- a/jwt/jwt.go
+++ b/jwt/jwt.go
@@ -6,6 +6,7 @@ package jwt
 
 import (
 	"bytes"
+	"errors"
 	"fmt"
 	"io"
 	"sync/atomic"
@@ -16,6 +17,15 @@ import (
 	"github.com/lestrrat-go/jwx/v2/jwt/internal/types"
 )
 
+var errInvalidJWT = errors.New(`invalid JWT`)
+
+// ErrInvalidJWT returns the opaque error value that is returned when
+// `jwt.Parse` fails due to not being able to deduce the format of
+// the incoming buffer
+func ErrInvalidJWT() error {
+	return errInvalidJWT
+}
+
 // Settings controls global settings that are specific to JWTs.
 func Settings(options ...GlobalOption) {
 	var flattenAudienceBool bool
@@ -263,11 +273,13 @@ OUTER:
 			}
 
 			break OUTER
+		case jwx.InvalidFormat:
+			return nil, ErrInvalidJWT()
 		case jwx.UnknownFormat:
 			// "Unknown" may include invalid JWTs, for example, those who lack "aud"
 			// claim. We could be pedantic and reject these
 			if ctx.pedantic {
-				return nil, fmt.Errorf(`invalid JWT`)
+				return nil, fmt.Errorf(`unknown JWT format (pedantic)`)
 			}
 
 			if i == 0 {
diff --git a/scripts/release.sh b/scripts/update-mods.sh
similarity index 75%
rename from scripts/release.sh
rename to scripts/update-mods.sh
index ae8d06ca..a2ed3d8d 100755
--- a/scripts/release.sh
+++ b/scripts/update-mods.sh
@@ -8,13 +8,14 @@ if [[ -z "$TAG" ]]; then
 fi
 
 # Make sure Changes file contains an entry for this release
-relentry=$(grep "$TAG" Changes)
+relentry=$(grep "$TAG" Changes | head -n 1)
 if [[ "$?" -ne 0 ]]; then
 	echo "$TAG does not exist in Changes file";
 	exit 1;
 fi
 
 reldate=${relentry#$TAG - }
+reldate=${reldate//['$\t\n\r']}
 parseddate=$(date --date="$reldate" "+%d %b %Y")
 
 if [[ "$reldate" != "$parseddate" ]]; then
@@ -27,13 +28,8 @@ for dir in ./cmd/jwx ./examples ./bench/performance; do
 	echo "👉 $dir"
 	pushd $dir > /dev/null
 
-	go mod edit -require=github.com/lestrrat-go/jwx/v2@"$TAG"
+	go get github.com/lestrrat-go/jwx/v2@"$TAG"
 	go mod tidy
 
 	popd > /dev/null
 done
-
-# set up tag
-git tag "$TAG"
-
-echo "tag $TAG has been created. Make sure to commit/push/push --tags afterwards"


Test patch:
diff --git a/examples/jws_verify_detached_payload_example_test.go b/examples/jws_verify_detached_payload_example_test.go
index bd063504..87cfb0a3 100644
--- a/examples/jws_verify_detached_payload_example_test.go
+++ b/examples/jws_verify_detached_payload_example_test.go
@@ -20,7 +20,7 @@ func ExampleJWS_VerifyDetachedPayload() {
 
 	verified, err := jws.Verify([]byte(serialized), jws.WithKey(jwa.HS256, key), jws.WithDetachedPayload([]byte(payload)))
 	if err != nil {
-		fmt.Printf("failed to sign payload: %s\n", err)
+		fmt.Printf("failed to verify payload: %s\n", err)
 		return
 	}
 
diff --git a/examples/jws_verify_with_key_example_test.go b/examples/jws_verify_with_key_example_test.go
index 5b547d48..973642e1 100644
--- a/examples/jws_verify_with_key_example_test.go
+++ b/examples/jws_verify_with_key_example_test.go
@@ -19,7 +19,7 @@ func ExampleJWS_VerifyWithKey() {
 
 	buf, err := jws.Verify([]byte(src), jws.WithKey(jwa.HS256, key))
 	if err != nil {
-		fmt.Printf("failed to sign payload: %s\n", err)
+		fmt.Printf("failed to verify payload: %s\n", err)
 		return
 	}
 	fmt.Printf("%s\n", buf)
diff --git a/jwe/jwe_test.go b/jwe/jwe_test.go
index a729b041..d3732ac8 100644
--- a/jwe/jwe_test.go
+++ b/jwe/jwe_test.go
@@ -819,3 +819,25 @@ func TestGH803(t *testing.T) {
 	require.Equal(t, apu, msg.ProtectedHeaders().AgreementPartyUInfo())
 	require.Equal(t, apv, msg.ProtectedHeaders().AgreementPartyVInfo())
 }
+
+func TestGH840(t *testing.T) {
+	// Go 1.19+ panics if elliptic curve operations are called against
+	// a point that's _NOT_ on the curve
+	untrustedJWK := []byte(`{
+		"kty": "EC",
+		"crv": "P-256",
+		"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqx7D4",
+		"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
+		"d": "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE"
+	}`)
+
+	privkey, err := jwk.ParseKey(untrustedJWK)
+	require.NoError(t, err, `jwk.ParseKey should succeed`)
+
+	pubkey, err := privkey.PublicKey()
+	require.NoError(t, err, `privkey.PublicKey should succeed`)
+
+	const payload = `Lorem ipsum`
+	_, err = jwe.Encrypt([]byte(payload), jwe.WithKey(jwa.ECDH_ES_A128KW, pubkey))
+	require.Error(t, err, `jwe.Encrypt should fail (instead of panic)`)
+}
diff --git a/jws/jws_test.go b/jws/jws_test.go
index 96997d1c..414df701 100644
--- a/jws/jws_test.go
+++ b/jws/jws_test.go
@@ -28,6 +28,7 @@ import (
 	"github.com/lestrrat-go/jwx/v2/jwa"
 	"github.com/lestrrat-go/jwx/v2/jwk"
 	"github.com/lestrrat-go/jwx/v2/jws"
+	"github.com/lestrrat-go/jwx/v2/jwt"
 	"github.com/lestrrat-go/jwx/v2/x25519"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -1919,3 +1920,34 @@ func TestGH681(t *testing.T) {
 		return
 	}
 }
+
+func TestGH840(t *testing.T) {
+	// Go 1.19+ panics if elliptic curve operations are called against
+	// a point that's _NOT_ on the curve
+	untrustedJWK := []byte(`{
+		"kty": "EC",
+		"crv": "P-256",
+		"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqx7D4",
+		"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
+		"d": "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE"
+	}`)
+
+	// Parse, serialize, slice and dice JWKs!
+	privkey, err := jwk.ParseKey(untrustedJWK)
+	require.NoError(t, err, `jwk.ParseKey should succeed`)
+
+	pubkey, err := jwk.PublicKeyOf(privkey)
+	require.NoError(t, err, `jwk.PublicKeyOf should succeed`)
+
+	tok, err := jwt.NewBuilder().
+		Issuer(`github.com/lestrrat-go/jwx`).
+		IssuedAt(time.Now()).
+		Build()
+	require.NoError(t, err, `jwt.NewBuilder should succeed`)
+
+	signed, err := jwt.Sign(tok, jwt.WithKey(jwa.ES256, privkey))
+	require.NoError(t, err, `jwt.Sign should succeed`)
+
+	_, err = jwt.Parse(signed, jwt.WithKey(jwa.ES256, pubkey))
+	require.Error(t, err, `jwt.Parse should FAIL`) // pubkey's X/Y is not on the curve
+}
diff --git a/jwt/jwt_test.go b/jwt/jwt_test.go
index d5f13a81..616f4c64 100644
--- a/jwt/jwt_test.go
+++ b/jwt/jwt_test.go
@@ -8,6 +8,7 @@ import (
 	"crypto/rand"
 	"crypto/rsa"
 	"encoding/base64"
+	"errors"
 	"fmt"
 	"net/http"
 	"net/http/httptest"
@@ -1659,3 +1660,10 @@ func TestGH836(t *testing.T) {
 	t2.Options().Disable(jwt.FlattenAudience)
 	require.True(t, t1.Options().IsEnabled(jwt.FlattenAudience), `flag should be enabled (t2.Options should have no effect on t1.Options)`)
 }
+
+func TestGH850(t *testing.T) {
+	var testToken = `eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjY2MDkxMzczLCJmb28iOiJiYXIifQ.3GWevx1z2_uCBB9Vj-D0rsT_CMsMeP9GP2rEqGDWpesoG8nHEjAXJOEQV1jOVkkCtTnS18JhcQdb7dW4i-zmqg.trailing-rubbish`
+
+	_, err := jwt.Parse([]byte(testToken), jwt.WithVerify(false))
+	require.True(t, errors.Is(err, jwt.ErrInvalidJWT()))
+}
diff --git a/tools/test.sh b/tools/test.sh
new file mode 100755
index 00000000..b8236fab
--- /dev/null
+++ b/tools/test.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+ROOT=$(cd $(dirname $0)/..; pwd -P)
+DST="$ROOT/coverage.out"
+if [[ -e "$DST" ]]; then
+	rm "$DST"
+fi
+
+testopts=($TESTOPTS)
+
+tmpfile=coverage.out.tmp
+case "$MODE" in
+	"cover")
+		testopts+=("-coverpkg=./...")
+		testopts+=("-coverprofile=$tmpfile")
+		;;
+	"short")
+		testopts+=("-short")
+		;;
+esac
+
+echo "mode: atomic" > "$DST"
+for dir in . ./examples ./bench/performance ./cmd/jwx; do
+	pushd "$dir" > /dev/null
+	go test -race -json ${testopts[@]} ./... | tparse
+	if [[ -e "$tmpfile" ]]; then
+		cat "$tmpfile" | tail -n +2 | grep -v "internal/jose" | grep -v "internal/jwxtest" | grep -v "internal/cmd" >> "$DST"
+		rm "$tmpfile"
+	fi
+	popd > /dev/null
+done