diff --git a/design/mvp/Binary.md b/design/mvp/Binary.md
index f8aa2772..33029e18 100644
--- a/design/mvp/Binary.md
+++ b/design/mvp/Binary.md
@@ -287,6 +287,7 @@ Notes:
`none` case of an optional immediate.)
* 🔧 for fixed-sized lists the length of the list must be larger than 0 to pass
validation.
+* Validation requires that, for every `defvaltype` `t`, `elem_size(t, 'i64')` is less than 228, as defined by the [Canonical ABI](CanonicalABI.md#element-size).
## Canonical Definitions
diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md
index 621296b5..febc1b23 100644
--- a/design/mvp/CanonicalABI.md
+++ b/design/mvp/CanonicalABI.md
@@ -2306,7 +2306,10 @@ byte size be a static property of the type instead of attempting to use a
variable-length element-encoding scheme both simplifies the implementation and
maps well to languages which represent `list`s as random-access arrays. Empty
types, such as records with no fields, are not permitted, to avoid
-complications in source languages.
+complications in source languages. To prevent integer overflow in obscure corner
+cases, component validation rules require that for every value type `t` defined
+by a component, `elem_size(t, 'i64')` is less than 228 (the same
+upper bound as `MAX_LIST_BYTE_LENGTH`).
```python
def elem_size(t, ptr_type):
match despecialize(t):
@@ -3594,6 +3597,8 @@ performed for a component. These are defined as:
* `lift(T)`
* requires `realloc` if `T` contains a `list` or `string`
+Value types used by `lift`/`lower` are already rejected at `defvaltype`
+definition if they exceed the [Element Size](#element-size) bound.
### `canon lift`
diff --git a/design/mvp/Explainer.md b/design/mvp/Explainer.md
index 28d51969..766c59ce 100644
--- a/design/mvp/Explainer.md
+++ b/design/mvp/Explainer.md
@@ -658,6 +658,11 @@ where bind-id(X) parses '(' sort ? Y ')' when X parses '(' sort Y ')'
Because there is nothing in this type grammar analogous to the [gc] proposal's
[`rectype`], none of these types are recursive.
+To prevent integer overflow in obscure corner cases, as an extra validation
+requirement, `defvaltype`s may not be equal or greater than 228 bytes
+when serialized into linear memory according to the `i64` ABI definition of
+[Element Size](CanonicalABI.md#element-size).
+
#### Fundamental value types
The value types in `valtype` can be broken into two categories: *fundamental*
diff --git a/test/nyi.txt b/test/nyi.txt
index ffb2d182..8f3e4250 100644
--- a/test/nyi.txt
+++ b/test/nyi.txt
@@ -1,4 +1,5 @@
# See README.md
+./validation/max-value-size.wast
./async/during-sync-call-may-block-if-other-ready-threads.wast
./async/during-sync-call-no-exclusive-resume.wast
./async/during-sync-call-no-sibling-resume.wast
diff --git a/test/validation/max-value-size.wast b/test/validation/max-value-size.wast
new file mode 100644
index 00000000..d26f99b2
--- /dev/null
+++ b/test/validation/max-value-size.wast
@@ -0,0 +1,65 @@
+;; Validation requires elem_size(t, i64) < 2^28 for every defvaltype t.
+;; See CanonicalABI.md#element-size.
+
+;; valid boundaries (single component)
+
+(component
+ (type (list u8 268435455))
+ (type (list u64 33554431))
+ (type (list string 16777215))
+ (type (map u8 (list u8 4)))
+ (type (tuple (list u8 268435454) (list u8 1)))
+ (type (record
+ (field "a" (list u8 134217727))
+ (field "b" (list u8 134217728))))
+ (type (list (list u8 134217727) 2))
+ (type (map u8 (list u8 268435455)))
+ (type (option (map u8 (list u8 268435455))))
+ (type (record (field "m" (map u8 (list u8 268435455)))))
+ (type (stream (list u8 268435455)))
+ (type (future (list u8 268435455)))
+)
+
+;; single fixed list just over the limit
+
+(assert_invalid
+ (component (type (list u8 268435456)))
+ "exceeds maximum byte size")
+
+;; fixed list whose product exceeds MAX
+
+(assert_invalid
+ (component (type (list u64 33554432)))
+ "exceeds maximum byte size")
+
+;; u32 wrap class: real byte size is 2^32 but naive u32 multiply wraps to 0
+
+(assert_invalid
+ (component (type (list u64 536870912)))
+ "exceeds maximum byte size")
+
+;; compound sum exceeds MAX
+
+(assert_invalid
+ (component
+ (type (tuple (list u8 268435455) (list u8 1))))
+ "exceeds maximum byte size")
+
+(assert_invalid
+ (component
+ (type (record
+ (field "a" (list u8 134217728))
+ (field "b" (list u8 134217728)))))
+ "exceeds maximum byte size")
+
+;; nested fixed list
+
+(assert_invalid
+ (component (type (list (list u8 268435455) 2)))
+ "exceeds maximum byte size")
+
+;; pointer-width-sensitive rejection (passes i32, fails i64)
+
+(assert_invalid
+ (component (type (list string 16777216)))
+ "exceeds maximum byte size")