system: You are an expert security code reviewer. You will be shown a source code file along with a catalog of candidate CWE (Common Weakness Enumeration) categories with their official MITRE names. Your task is to list every distinct CWE from that catalog that is actually present in the code. The catalog is comprehensive for this dataset -- the answer is a (possibly small) subset of it.

OUTPUT FORMAT: Respond with a comma-separated list of CWE IDs in the form `CWE-N`, sorted in ascending numeric order, wrapped in a single \boxed{...}. Examples: `\boxed{CWE-79}` for one, `\boxed{CWE-22,CWE-79,CWE-327}` for three. Output the boxed answer ONLY -- no explanation, no other text.

user: ```python
# coding=utf-8
# Copyright 2019 The Google Research Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Functions to validate lexicon entries."""

import re
from typing import Dict, Generator, Tuple

from src.analyzer.lexicon import tags

_FeatureCategoryValuePair = Tuple[str, str]
_LexiconEntry = Dict[str, str]

_FEATURE_CATEGORY_VALUE_REGEX = re.compile(r"\+\[([A-z0-9]+?)=([A-z0-9]+?)\]")
_FEATURES_REGEX = re.compile(r"(?:\+\[[A-z0-9]+?=[A-z0-9]+?\])+")
_REQUIRED_FIELDS = set([
    "tag",
    "root",
    "morphophonemics",
    "features",
    "is_compound",
])


class InvalidLexiconEntryError(Exception):
  """Raised when a lexicon entry is illformed."""


def _tag_of(entry: _LexiconEntry) -> str:
  """Returns normalized tag annotation of the entry."""
  return entry["tag"].upper()


def _morphophonemics_of(entry: _LexiconEntry) -> str:
  """Returns morphophonemics annotation of the entry."""
  return entry["morphophonemics"]


def _features_of(entry: _LexiconEntry) -> str:
  """Returns features annotation of the entry."""
  return entry["features"]


def _is_compound_of(entry: _LexiconEntry) -> str:
  """Returns normalized compound annotation of the entry."""
  return entry["is_compound"].lower()


def _category_value_pairs(
    features: str) -> Generator[_FeatureCategoryValuePair, None, None]:
  """Extracts feature category-value pairs from features annotation string."""
  yield from (f for f in _FEATURE_CATEGORY_VALUE_REGEX.findall(features) if f)


def _entry_has_required_fields(entry: _LexiconEntry) -> None:
  """Checks if entry has all required fields to create a rewrite rule."""
  missing_fields = [f for f in _REQUIRED_FIELDS if f not in entry]

  if missing_fields:
    field_str = ", ".join(sorted(missing_fields))
    raise InvalidLexiconEntryError(f"Entry is missing fields: '{field_str}'")


def _entry_field_values_are_not_empty(entry: _LexiconEntry) -> None:
  """Checks if all required entry fields have non-empty values."""
  empty_fields = [f for f in _REQUIRED_FIELDS if not entry[f]]

  if empty_fields:
    field_str = ", ".join(sorted(empty_fields))
    raise InvalidLexiconEntryError(
        f"Entry fields have empty values: '{field_str}'")


def _entry_field_values_does_not_contain_infix_whitespace(
    entry: _LexiconEntry) -> None:
  """Checks if entry has single token tag, morphophonemics and feature value."""

  def _has_multi_token_value(field: str) -> bool:
    return len(entry[field].split()) != 1

  fields_to_check = ("tag", "morphophonemics", "features")
  multi_token_fields = [f for f in fields_to_check if _has_multi_token_value(f)]

  if multi_token_fields:
    field_str = ", ".join(sorted(multi_token_fields))
    raise InvalidLexiconEntryError(
        f"Entry field values contain whitespace: '{field_str}'")


def _entry_tag_is_valid(entry: _LexiconEntry) -> None:
  """Checks if entry tag is valid."""
  tag = _tag_of(entry)

  if tag not in tags.VALID_TAGS:
    raise InvalidLexiconEntryError(
        "Entry 'tag' field has invalid value. It can only be one of the valid"
        " tags that are defined in 'morphotactics_compiler/tags.py'.")


def _entry_compound_annotation_is_valid(entry: _LexiconEntry) -> None:
  """Checks if entry compound annotation is valid ('true' or 'false')."""
  compound = _is_compound_of(entry)
  valid_values = ("true", "false")

  if compound not in valid_values:
    raise InvalidLexiconEntryError(
        "Entry 'is_compound' field has invalid value. It can only have the"
        " values 'true' or 'false'.")


def _entry_morphophonemics_annotation_is_valid(entry: _LexiconEntry) -> None:
  """Checks if entry has a morphophonemics annotation if it is a compound."""
  compound = _is_compound_of(entry)
  morphophonemics = _morphophonemics_of(entry)

  if compound == "true" and morphophonemics == "~":
    raise InvalidLexiconEntryError(
        "Entry is marked as ending with compounding marker but it is missing"
        " morphophonemics annotation.")


def _entry_features_annotation_is_valid(entry: _LexiconEntry) -> None:
  """Checks if entry features annotation is valid (e.g. '+[Cat=Tag]...')."""
  features = _features_of(entry)

  if not (features == "~" or _FEATURES_REGEX.fullmatch(features)):
    raise InvalidLexiconEntryError(
        "Entry features annotation is invalid. Features need to be annotated"
        " as '+[Category_1=Value_x]...+[Category_n=Value_y].")


def _entry_has_required_features(entry: _LexiconEntry) -> None:
  """Checks if entry has features if its expected to have required features."""
  features = _features_of(entry)
  tag = _tag_of(entry)
  required = tags.REQUIRED_FEATURES[tag]

  if features == "~" and required:
    raise InvalidLexiconEntryError("Entry is missing required features.")


def _entry_required_features_are_valid(entry: _LexiconEntry) -> None:
  """Checks if entry has the expected set of required features."""
  tag = _tag_of(entry)
  required = tags.REQUIRED_FEATURES[tag]

  if not required:
    return

  features = _features_of(entry)
  category_value = _category_value_pairs(features)
  categories, values = zip(*category_value)

  if categories != tuple(required.keys()):
    raise InvalidLexiconEntryError(
        "Entry has invalid required feature category.")

  if any(v not in r for v, r in zip(values, required.values())):
    raise InvalidLexiconEntryError("Entry has invalid required feature value.")


def _entry_optional_features_are_valid(entry: _LexiconEntry) -> None:
  """Checks if optional features of the entry are valid."""
  tag = _tag_of(entry)
  optional = tags.OPTIONAL_FEATURES[tag]

  if not optional:
    return

  features = _features_of(entry)
  category_value = _category_value_pairs(features)

  if not all(c in optional and v in optional[c] for c, v in category_value):
    raise InvalidLexiconEntryError("Entry has invalid optional features.")


def _entry_features_are_not_redundant(entry: _LexiconEntry) -> None:
  """Checks if entry doesn't have features if its not expected to have any."""
  features = _features_of(entry)
  tag = _tag_of(entry)
  required = tags.REQUIRED_FEATURES[tag]
  optional = tags.OPTIONAL_FEATURES[tag]

  if not (required or optional) and features != "~":
    raise InvalidLexiconEntryError(
        "Entry has features while it is not expected to have any.")


def validate(entry: _LexiconEntry) -> None:
  """Checks if lexicon entry is wellformed.

  Args:
    entry: lexicon entry whose validity will be checked.

  Raises:
    InvalidLexiconEntryError: lexicon entry is missing a non-empty required
        annotation field (that are defined in the _REQUIRED_FIELDS list), or
        one of its fields ('tag', 'morphophonemics', 'features') has an
        annotation that contains whitespace, or its features annotation is
        invalid.
  """
  _entry_has_required_fields(entry)
  _entry_field_values_are_not_empty(entry)
  _entry_field_values_does_not_contain_infix_whitespace(entry)
  _entry_tag_is_valid(entry)
  _entry_compound_annotation_is_valid(entry)
  _entry_morphophonemics_annotation_is_valid(entry)
  _entry_features_annotation_is_valid(entry)
  _entry_has_required_features(entry)
  _entry_required_features_are_valid(entry)
  _entry_optional_features_are_valid(entry)
  _entry_features_are_not_redundant(entry)

```

Candidate CWE catalog (every CWE that appears anywhere in this dataset):
  - CWE-20: Improper Input Validation
  - CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
  - CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
  - CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
  - CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
  - CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
  - CWE-94: Improper Control of Generation of Code ('Code Injection')
  - CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Request/Response Splitting')
  - CWE-116: Improper Encoding or Escaping of Output
  - CWE-117: Improper Output Neutralization for Logs
  - CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
  - CWE-209: Generation of Error Message Containing Sensitive Information
  - CWE-215: Insertion of Sensitive Information Into Debugging Code
  - CWE-295: Improper Certificate Validation
  - CWE-312: Cleartext Storage of Sensitive Information
  - CWE-326: Inadequate Encryption Strength
  - CWE-327: Use of a Broken or Risky Cryptographic Algorithm
  - CWE-377: Insecure Temporary File
  - CWE-502: Deserialization of Untrusted Data
  - CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
  - CWE-611: Improper Restriction of XML External Entity Reference
  - CWE-614: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute
  - CWE-643: Improper Neutralization of Data within XPath Expressions ('XPath Injection')
  - CWE-730: OWASP Top Ten 2004 Category A9 - Denial of Service
  - CWE-732: Incorrect Permission Assignment for Critical Resource
  - CWE-776: Improper Restriction of Recursive Entity References in DTDs ('XML Entity Expansion')
  - CWE-918: Server-Side Request Forgery (SSRF)
  - CWE-943: Improper Neutralization of Special Elements in Data Query Logic
  - CWE-1004: Sensitive Cookie Without 'HttpOnly' Flag
  - CWE-1333: Inefficient Regular Expression Complexity

List every distinct CWE from the catalog above that is actually present in this code.
Answer: CWE-20